diff --git a/ci/build.sh b/ci/build.sh index 4c26ab9ce..aaa99db2f 100755 --- a/ci/build.sh +++ b/ci/build.sh @@ -1,74 +1,81 @@ #!/usr/bin/env bash set -o pipefail [[ "${DEBUG:-}" ]] && set -x declare -i failed failed=0 # SC2046: Quote this to prevent word splitting. # SC1090: Can't follow non-constant source. Use a directive to specify location. # SC2039: In POSIX sh, 'local' is undefined. # SC2086: Double quote to prevent globbing and word splitting. # SC2154: var is referenced but not assigned. ignored_errors="SC1090,SC2039,SC2154" success() { printf "\r\033[2K [ \033[00;32mOK\033[0m ] Checking %s...\n" "$1" } warn() { printf "\r\033[2K [\033[0;33mWARNING\033[0m] Checking %s...\n" "$1" } fail() { printf "\r\033[2K [\033[0;31mFAIL\033[0m] Checking %s...\n" "$1" - failed=1 + failed=$((failed + 1)) } check() { local script="$1" out="$(shellcheck -s sh -f gcc -x -e "$ignored_errors" "$script" 2>&1)" rc=$? if [ $rc -eq 0 ]; then success "$script" elif echo "$out" | grep -i 'error' >/dev/null; then fail "$script" else warn "$script" fi echo "$out" } find_prunes() { local prunes="! -path './.git/*'" if [ -f .gitmodules ]; then while read -r module; do prunes="$prunes ! -path './$module/*'" done < <(grep path .gitmodules | awk '{print $3}') fi echo "$prunes" } find_cmd() { echo "find heartbeat -type f -and \( -perm /111 -or -name '*.sh' \) $(find_prunes)" } check_all_executables() { echo "Checking executables and .sh files..." while read -r script; do + file --mime "$script" | grep 'charset=binary' >/dev/null 2>&1 && continue head=$(head -n1 "$script") [[ "$head" =~ .*ruby.* ]] && continue [[ "$head" =~ .*zsh.* ]] && continue [[ "$head" =~ ^#compdef.* ]] && continue - [[ "$head" =~ ^.*\.c ]] && continue - [[ "$head" =~ ^ldirectord.in ]] && continue + [[ "$script" =~ ^.*\.c ]] && continue + [[ "$script" =~ ^.*\.orig ]] && continue + [[ "$script" =~ ^ldirectord.in ]] && continue check "$script" done < <(eval "$(find_cmd)") - exit $failed + if [ $failed -gt 0 ]; then + echo "$failed failures detected." + exit 1 + fi + exit 0 } ./autogen.sh ./configure make +[ $? ] || failed=$((failed + 1)) check_all_executables diff --git a/heartbeat/ClusterMon b/heartbeat/ClusterMon index 0e1566440..95cb860c0 100755 --- a/heartbeat/ClusterMon +++ b/heartbeat/ClusterMon @@ -1,261 +1,261 @@ #!/bin/sh # # # ClusterMon OCF RA. # Starts crm_mon in background which logs cluster status as # html to the specified file. # -# Copyright (c) 2004 SUSE LINUX AG, Lars Marowsky-Brée +# Copyright (c) 2004 SUSE LINUX AG, Lars Marowsky-Bree # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # Further, this software is distributed without any warranty that it is # free of the rightful claim of any third person regarding infringement # or the like. Any license provided herein, whether implied or # otherwise, applies only to this software file. Patent licenses, if # any, provided herein do not apply to combinations of this program with # other software, or any other product whatsoever. # # You should have received a copy of the GNU General Public License # along with this program; if not, write the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. # # OCF instance parameters: # OCF_RESKEY_user # OCF_RESKEY_pidfile # OCF_RESKEY_update # OCF_RESKEY_extra_options # OCF_RESKEY_htmlfile ####################################################################### # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ####################################################################### meta_data() { cat < 1.0 This is a ClusterMon Resource Agent. It outputs current cluster status to the html. Runs crm_mon in the background, recording the cluster status to an HTML file The user we want to run crm_mon as The user we want to run crm_mon as How frequently should we update the cluster status Update interval Additional options to pass to crm_mon. Eg. -n -r Extra options PID file location to ensure only one instance is running PID file Location to write HTML output to. HTML output END } ####################################################################### ClusterMon_usage() { cat </dev/null if [ $? -eq 0 ]; then : Yes, user exists. We can further check his permission on crm_mon if necessary else ocf_log err "The user $OCF_RESKEY_user does not exist!" exit $OCF_ERR_ARGS fi fi # Pidfile better be an absolute path case $OCF_RESKEY_pidfile in /*) ;; *) ocf_log warn "You should have pidfile($OCF_RESKEY_pidfile) of absolute path!" ;; esac # Check the update interval if ocf_is_decimal "$OCF_RESKEY_update" && [ $OCF_RESKEY_update -gt 0 ]; then : else ocf_log err "Invalid update interval $OCF_RESKEY_update. It should be positive integer!" exit $OCF_ERR_ARGS fi if CheckOptions $OCF_RESKEY_extra_options; then : else ocf_log err "Invalid options $OCF_RESKEY_extra_options!" exit $OCF_ERR_ARGS fi # Htmlfile better be an absolute path case $OCF_RESKEY_htmlfile in /*) ;; *) ocf_log warn "You should have htmlfile($OCF_RESKEY_htmlfile) of absolute path!" ;; esac echo "Validate OK" return $OCF_SUCCESS } if [ $# -ne 1 ]; then ClusterMon_usage exit $OCF_ERR_ARGS fi : ${OCF_RESKEY_update:="15000"} : ${OCF_RESKEY_pidfile:="/tmp/ClusterMon_${OCF_RESOURCE_INSTANCE}.pid"} : ${OCF_RESKEY_htmlfile:="/tmp/ClusterMon_${OCF_RESOURCE_INSTANCE}.html"} OCF_RESKEY_update=`expr $OCF_RESKEY_update / 1000` case $__OCF_ACTION in meta-data) meta_data exit $OCF_SUCCESS ;; start) ClusterMon_start ;; stop) ClusterMon_stop ;; monitor) ClusterMon_monitor ;; validate-all) ClusterMon_validate ;; usage|help) ClusterMon_usage exit $OCF_SUCCESS ;; *) ClusterMon_usage exit $OCF_ERR_UNIMPLEMENTED ;; esac exit $? diff --git a/heartbeat/Dummy b/heartbeat/Dummy index a0929fac0..fac38af70 100755 --- a/heartbeat/Dummy +++ b/heartbeat/Dummy @@ -1,180 +1,180 @@ #!/bin/sh # # # Dummy OCF RA. Does nothing but wait a few seconds, can be # configured to fail occassionally. # -# Copyright (c) 2004 SUSE LINUX AG, Lars Marowsky-Brée +# Copyright (c) 2004 SUSE LINUX AG, Lars Marowsky-Bree # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # Further, this software is distributed without any warranty that it is # free of the rightful claim of any third person regarding infringement # or the like. Any license provided herein, whether implied or # otherwise, applies only to this software file. Patent licenses, if # any, provided herein do not apply to combinations of this program with # other software, or any other product whatsoever. # # You should have received a copy of the GNU General Public License # along with this program; if not, write the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. # ####################################################################### # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ####################################################################### meta_data() { cat < 1.0 This is a Dummy Resource Agent. It does absolutely nothing except keep track of whether its running or not. Its purpose in life is for testing and to serve as a template for RA writers. NB: Please pay attention to the timeouts specified in the actions section below. They should be meaningful for the kind of resource the agent manages. They should be the minimum advised timeouts, but they shouldn't/cannot cover _all_ possible resource instances. So, try to be neither overly generous nor too stingy, but moderate. The minimum timeouts should never be below 10 seconds. Example stateless resource agent Location to store the resource state in. State file Fake attribute that can be changed to cause a reload Fake attribute that can be changed to cause a reload END } ####################################################################### dummy_usage() { cat < 1.0 This is a SysInfo Resource Agent. It records (in the CIB) various attributes of a node Sample Linux output: arch: i686 os: Linux-2.4.26-gentoo-r14 free_swap: 1999 cpu_info: Intel(R) Celeron(R) CPU 2.40GHz cpu_speed: 4771.02 cpu_cores: 1 cpu_load: 0.00 ram_total: 513 ram_free: 117 root_free: 2.4 Sample Darwin output: arch: i386 os: Darwin-8.6.2 cpu_info: Intel Core Duo cpu_speed: 2.16 cpu_cores: 2 cpu_load: 0.18 ram_total: 2016 ram_free: 787 root_free: 13 Units: free_swap: Mb ram_*: Mb root_free: Gb cpu_speed (Linux): bogomips cpu_speed (Darwin): Ghz Records various node attributes in the CIB PID file PID file Interval to allow values to stabilize Dampening Delay END } ####################################################################### UpdateStat() { name=$1; shift value="$*" echo -e "$name:\t$value" ${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -S status -n $name -v "$value" } SysInfoStats() { UpdateStat arch "`uname -m`" UpdateStat os "`uname -s`-`uname -r`" case `uname -s` in "Darwin") mem=`top -l 1 | grep Mem: | awk '{print $10}'` mem_used=`top -l 1 | grep Mem: | awk '{print $8}'` mem=`SysInfo_mem_units $mem` mem_used=`SysInfo_mem_units $mem_used` mem_total=`expr $mem_used + $mem` cpu_type=`system_profiler SPHardwareDataType | grep "CPU Type:"` cpu_type=${cpu_type/*: /} cpu_speed=`system_profiler SPHardwareDataType | grep "CPU Speed:" | awk '{print $3}'` cpu_cores=`system_profiler SPHardwareDataType | grep "Number Of"` cpu_cores=${cpu_cores/*: /} ;; "Linux") if [ -f /proc/cpuinfo ]; then cpu_type=`grep "model name" /proc/cpuinfo | head -n 1` cpu_type=${cpu_type/*: /} cpu_speed=`grep "bogomips" /proc/cpuinfo | head -n 1` cpu_speed=${cpu_speed/*: /} cpu_cores=`grep "^processor" /proc/cpuinfo | wc -l` fi if [ -f /proc/meminfo ]; then # meminfo results are in kB mem=`grep "SwapFree" /proc/meminfo | awk '{print $2"k"}'` if [ ! -z $mem ]; then UpdateStat free_swap `SysInfo_mem_units $mem` fi mem=`grep "Inactive" /proc/meminfo | awk '{print $2"k"}'` mem_total=`grep "MemTotal" /proc/meminfo | awk '{print $2"k"}'` else mem=`top -n 1 | grep Mem: | awk '{print $7}'` fi ;; *) esac if [ x != x"$cpu_type" ]; then UpdateStat cpu_info "$cpu_type" fi if [ x != x"$cpu_speed" ]; then UpdateStat cpu_speed "$cpu_speed" fi if [ x != x"$cpu_cores" ]; then UpdateStat cpu_cores "$cpu_cores" fi loads=`uptime` load15=`echo ${loads} | awk '{print $10}'` UpdateStat cpu_load $load15 if [ ! -z "$mem" ]; then # Massage the memory values UpdateStat ram_total `SysInfo_mem_units $mem_total` UpdateStat ram_free `SysInfo_mem_units $mem` fi # Portability notes: # o df: -h flag not available on Solaris 8. (OK on 9, 10, ...) #FIXME# # o tail: explicit "-n" not available in Solaris; instead simplify # 'tail -n ' to the equivalent 'tail -'. disk=`df -h / | tail -1 | awk '{print $4}'` if [ x != x"$disk" ]; then UpdateStat root_free `SysInfo_hdd_units $disk` fi } SysInfo_mem_units() { mem=$1 if [ -z $1 ]; then return fi memlen=`expr ${#mem} - 1` memlen_alt=`expr ${#mem} - 2` if [ ${mem:$memlen:1} = "G" ]; then mem="${mem:0:$memlen}" if [ $mem != ${mem/./} ]; then mem_before=${mem/.*/} mem_after=${mem/*./} mem=$[mem_before*1024] if [ ${#mem_after} = 0 ]; then : elif [ ${#mem_after} = 1 ]; then mem=$[mem+100*$mem_after] elif [ ${#mem_after} = 2 ]; then mem=$[mem+10*$mem_after] elif [ ${#mem_after} = 3 ]; then mem=$[mem+$mem_after] else mem_after=${mem_after:0:3} mem=$[mem+$mem_after] fi fi elif [ ${mem:$memlen:1} = "M" ]; then mem=${mem/.*/} mem="${mem:0:$memlen}" elif [ ${mem:$memlen:1} = "k" ]; then mem="${mem:0:$memlen}" mem=${mem/.*/} mem=`expr $mem / 1024` elif [ ${mem:$memlen_alt:2} = "kB" ]; then mem="${mem:0:$memlen_alt}" mem=${mem/.*/} mem=`expr $mem / 1024` elif [ ${mem:$memlen_alt:2} = "Mb" ]; then mem="${mem:0:$memlen_alt}" mem=${mem/.*/} elif [ ${mem:$memlen_alt:2} = "MB" ]; then mem="${mem:0:$memlen_alt}" mem=${mem/.*/} fi # Round to the next multiple of 50 memlen=`expr ${#mem} - 2` mem_round="${mem:$memlen:2}" if [ x$mem_round = x ]; then : elif [ $mem_round = "00" ]; then : else mem_round=`echo $mem_round | sed 's/^0//'` if [ $mem_round -lt "50" ]; then mem=$[mem+50] mem=$[mem-$mem_round] else mem=$[mem+100] mem=$[mem-$mem_round] fi fi echo $mem } SysInfo_hdd_units() { disk=$1 disklen=`expr ${#disk} - 1` disklen_alt=`expr ${#disk} - 2` if [ ${disk:$disklen:1} = "G" ]; then disk="${disk:0:$disklen}" elif [ ${disk:$disklen:1} = "M" ]; then disk="${disk:0:$disklen}" disk=${disk/.*/} disk=`expr $disk / 1024` elif [ ${disk:$disklen:1} = "k" ]; then disk="${disk:0:$disklen}" disk=${disk/.*/} disk=`expr $disk / 1048576` elif [ ${disk:$disklen_alt:2} = "kB" ]; then disk="${disk:0:$disklen_alt}" disk=${disk/.*/} disk=`expr $disk / 1048576` elif [ ${disk:$disklen_alt:2} = "Mb" ]; then disk="${disk:0:$disklen_alt}" disk=${disk/.*/} disk=`expr $disk / 1024` elif [ ${disk:$disklen_alt:2} = "MB" ]; then disk="${disk:0:$disklen_alt}" disk=${disk/.*/} disk=`expr $disk / 1024` fi echo $disk } SysInfo_usage() { cat < $OCF_RESKEY_pidfile SysInfoStats exit $OCF_SUCCESS } SysInfo_stop() { rm $OCF_RESKEY_pidfile exit $OCF_SUCCESS } SysInfo_monitor() { if [ -f $OCF_RESKEY_pidfile ]; then clone=`cat $OCF_RESKEY_pidfile` fi if [ x$clone = x ]; then rm $OCF_RESKEY_pidfile exit $OCF_NOT_RUNNING elif [ $clone = $OCF_RESKEY_clone ]; then SysInfoStats exit $OCF_SUCCESS elif [ x$OCF_RESKEY_CRM_meta_globally_unique = xtrue -o x$OCF_RESKEY_CRM_meta_globally_unique = xTrue -o x$OCF_RESKEY_CRM_meta_globally_unique = xyes -o x$OCF_RESKEY_CRM_meta_globally_unique = xYes ]; then SysInfoStats exit $OCF_SUCCESS fi exit $OCF_NOT_RUNNING } SysInfo_validate() { return $OCF_SUCCESS } if [ $# -ne 1 ]; then SysInfo_usage exit $OCF_ERR_ARGS fi : ${OCF_RESKEY_pidfile:="$HA_RSCTMP/SysInfo-${OCF_RESOURCE_INSTANCE}"} : ${OCF_RESKEY_clone:="0"} if [ x != x${OCF_RESKEY_delay} ]; then OCF_RESKEY_delay="-d ${OCF_RESKEY_delay}" fi case $__OCF_ACTION in meta-data) meta_data exit $OCF_SUCCESS ;; start) SysInfo_start ;; stop) SysInfo_stop ;; monitor) SysInfo_monitor ;; validate-all) SysInfo_validate ;; usage|help) SysInfo_usage exit $OCF_SUCCESS ;; *) SysInfo_usage exit $OCF_ERR_UNIMPLEMENTED ;; esac exit $? diff --git a/heartbeat/ethmonitor b/heartbeat/ethmonitor index 6563af767..7f5579f94 100755 --- a/heartbeat/ethmonitor +++ b/heartbeat/ethmonitor @@ -1,551 +1,551 @@ #!/bin/sh # # OCF Resource Agent compliant script. # Monitor the vitality of a local network interface. # -# Based on the work by Robert Euhus and Lars Marowsky-Brée. +# Based on the work by Robert Euhus and Lars Marowsky-Bree. # # Transfered from Ipaddr2 into ethmonitor by Alexander Krauth # # Copyright (c) 2011 Robert Euhus, Alexander Krauth, Lars Marowsky-Brée # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # Further, this software is distributed without any warranty that it is # free of the rightful claim of any third person regarding infringement # or the like. Any license provided herein, whether implied or # otherwise, applies only to this software file. Patent licenses, if # any, provided herein do not apply to combinations of this program with # other software, or any other product whatsoever. # # You should have received a copy of the GNU General Public License # along with this program; if not, write the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. # # OCF parameters are as below # # OCF_RESKEY_interface # OCF_RESKEY_multiplicator # OCF_RESKEY_name # OCF_RESKEY_repeat_count # OCF_RESKEY_repeat_interval # OCF_RESKEY_pktcnt_timeout # OCF_RESKEY_arping_count # OCF_RESKEY_arping_timeout # OCF_RESKEY_arping_cache_entries # # TODO: Check against IPv6 # ####################################################################### # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ####################################################################### meta_data() { cat < 1.2 Monitor the vitality of a local network interface. You may set up this RA as a clone resource to monitor the network interfaces on different nodes, with the same interface name. This is not related to the IP address or the network on which a interface is configured. You may use this RA to move resources away from a node, which has a faulty interface or prevent moving resources to such a node. This gives you independend control of the resources, without involving cluster intercommunication. But it requires your nodes to have more than one network interface. The resource configuration requires a monitor operation, because the monitor does the main part of the work. In addition to the resource configuration, you need to configure some location constraints, based on a CIB attribute value. The name of the attribute value is configured in the 'name' option of this RA. Example constraint configuration using crmsh location loc_connected_node my_resource_grp \ rule $id="rule_loc_connected_node" -INF: ethmonitor eq 0 Example constraint configuration using pcs. Only allow 'my_resource' to run on nodes where eth0 ethernet device is available. pcs constraint location my_resource rule score=-INFINITY ethmonitor-eth0 ne 1 The ethmonitor works in 3 different modes to test the interface vitality. 1. call ip to see if the link status is up (if link is down -> error) 2. call ip and watch the RX counter (if packages come around in a certain time -> success) 3. call arping to check whether any of the IPs found in the local ARP cache answers an ARP REQUEST (one answer -> success) 4. return error Monitors network interfaces The name of the network interface which should be monitored (e.g. eth0). Network interface name The name of the CIB attribute to set. This is the name to be used in the constraints. Defaults to "ethmonitor-'interface_name'". Attribute name Multiplier for the value of the CIB attriobute specified in parameter name. Multiplier for result variable Specify how often the interface will be monitored, before the status is set to failed. You need to set the timeout of the monitoring operation to at least repeat_count * repeat_interval Monitor repeat count Specify how long to wait in seconds between the repeat_counts. Monitor repeat interval in seconds Timeout for the RX packet counter. Stop listening for packet counter changes after the given number of seconds. packet counter timeout Number of ARP REQUEST packets to send for every IP. Usually one ARP REQUEST (arping) is send Number of arpings per IP Time in seconds to wait for ARP REQUESTs (all packets of arping_count). This is to limit the time for arp requests, to be able to send requests to more than one node, without running in the monitor operation timeout. Timeout for arpings per IP Maximum number of IPs from ARP cache list to check for ARP REQUEST (arping) answers. Newest entries are tried first. Number of ARP cache entries to try For interfaces that are infiniband devices. infiniband device For infiniband devices, this is the port to monitor. infiniband port Only report success based on link status. Do not perform RX counter or arping related connectivity tests. link status check only END exit $OCF_SUCCESS } # # Return true, if the interface exists # is_interface() { # # List interfaces but exclude FreeS/WAN ipsecN virtual interfaces # local iface=`$IP2UTIL -o -f inet addr show | grep " $1 " \ | cut -d ' ' -f2 | sort -u | grep -v '^ipsec[0-9][0-9]*$'` [ "$iface" != "" ] } infiniband_status() { local device="$OCF_RESKEY_infiniband_device" if [ -n "$OCF_RESKEY_infiniband_port" ]; then device="${OCF_RESKEY_infiniband_device}:${OCF_RESKEY_infiniband_port}" fi ibstatus ${device} | grep -q ACTIVE } if_init() { local rc if [ X"$OCF_RESKEY_interface" = "X" ]; then ocf_exit_reason "Interface name (the interface parameter) is mandatory" exit $OCF_ERR_CONFIGURED fi NIC="$OCF_RESKEY_interface" if is_interface $NIC then case "$NIC" in *:*) ocf_exit_reason "Do not specify a virtual interface : $OCF_RESKEY_interface" exit $OCF_ERR_CONFIGURED;; *) ;; esac else case $__OCF_ACTION in validate-all) ocf_exit_reason "Interface $NIC does not exist" exit $OCF_ERR_CONFIGURED;; *) ## It might be a bond interface which is temporarily not available, therefore we want to continue here ocf_log warn "Interface $NIC does not exist" ;; esac fi : ${OCF_RESKEY_multiplier:="1"} if ! ocf_is_decimal "$OCF_RESKEY_multiplier"; then ocf_exit_reason "Invalid OCF_RESKEY_multiplier [$OCF_RESKEY_multiplier]" exit $OCF_ERR_CONFIGURED fi ATTRNAME=${OCF_RESKEY_name:-"ethmonitor-$NIC"} REP_COUNT=${OCF_RESKEY_repeat_count:-5} if ! ocf_is_decimal "$REP_COUNT" -o [ $REP_COUNT -lt 1 ]; then ocf_exit_reason "Invalid OCF_RESKEY_repeat_count [$REP_COUNT]" exit $OCF_ERR_CONFIGURED fi REP_INTERVAL_S=${OCF_RESKEY_repeat_interval:-10} if ! ocf_is_decimal "$REP_INTERVAL_S"; then ocf_exit_reason "Invalid OCF_RESKEY_repeat_interval [$REP_INTERVAL_S]" exit $OCF_ERR_CONFIGURED fi : ${OCF_RESKEY_pktcnt_timeout:="5"} if ! ocf_is_decimal "$OCF_RESKEY_pktcnt_timeout"; then ocf_exit_reason "Invalid OCF_RESKEY_pktcnt_timeout [$OCF_RESKEY_pktcnt_timeout]" exit $OCF_ERR_CONFIGURED fi : ${OCF_RESKEY_arping_count:="1"} if ! ocf_is_decimal "$OCF_RESKEY_arping_count"; then ocf_exit_reason "Invalid OCF_RESKEY_arping_count [$OCF_RESKEY_arping_count]" exit $OCF_ERR_CONFIGURED fi : ${OCF_RESKEY_arping_timeout:="1"} if ! ocf_is_decimal "$OCF_RESKEY_arping_timeout"; then ocf_exit_reason "Invalid OCF_RESKEY_arping_timeout [$OCF_RESKEY_arping_count]" exit $OCF_ERR_CONFIGURED fi : ${OCF_RESKEY_arping_cache_entries:="5"} if ! ocf_is_decimal "$OCF_RESKEY_arping_cache_entries"; then ocf_exit_reason "Invalid OCF_RESKEY_arping_cache_entries [$OCF_RESKEY_arping_cache_entries]" exit $OCF_ERR_CONFIGURED fi if [ -n "$OCF_RESKEY_infiniband_device" ]; then #ibstatus is required if an infiniband_device is provided check_binary ibstatus fi return $OCF_SUCCESS } # get the link status on $NIC # asks ip about running (up) interfaces, returns the number of matching interface names that are up get_link_status () { $IP2UTIL -o link show up dev "$NIC" | grep -v 'NO-CARRIER' | grep -c "$NIC" } # returns the number of received rx packets on $NIC get_rx_packets () { ocf_log debug "$IP2UTIL -o -s link show dev $NIC" $IP2UTIL -o -s link show dev "$NIC" \ | sed 's/.* RX: [^0-9]*[0-9]* *\([0-9]*\) .*/\1/' # the first number after RX: is the # of bytes , # the second is the # of packets received } # watch for packet counter changes for max. OCF_RESKEY_pktcnt_timeout seconds # returns immedeately with return code 0 if any packets were received # otherwise 1 is returned watch_pkt_counter () { local RX_PACKETS_NEW local RX_PACKETS_OLD RX_PACKETS_OLD="`get_rx_packets`" for n in `seq $(( $OCF_RESKEY_pktcnt_timeout * 10 ))`; do sleep 0.1 RX_PACKETS_NEW="`get_rx_packets`" ocf_log debug "RX_PACKETS_OLD: $RX_PACKETS_OLD RX_PACKETS_NEW: $RX_PACKETS_NEW" if [ "$RX_PACKETS_OLD" -ne "$RX_PACKETS_NEW" ]; then ocf_log debug "we received some packets." return 0 fi done return 1 } # returns list of cached ARP entries for $NIC # sorted by age ("last confirmed") # max. OCF_RESKEY_arping_cache_entries entries get_arp_list () { $IP2UTIL -s neighbour show dev $NIC \ | sort -t/ -k2,2n | cut -d' ' -f1 \ | head -n $OCF_RESKEY_arping_cache_entries # the "used" entries in `ip -s neighbour show` are: # "last used"/"last confirmed"/"last updated" } # arping the IP given as argument $1 on $NIC # until OCF_RESKEY_arping_count answers are received do_arping () { # TODO: add the source IP # TODO: check for diffenrent arping versions out there arping -q -c $OCF_RESKEY_arping_count -w $OCF_RESKEY_arping_timeout -I $NIC $1 # return with the exit code of the arping command return $? } # # Check the interface depending on the level given as parameter: $OCF_RESKEY_check_level # # 09: check for nonempty ARP cache # 10: watch for packet counter changes # # 19: check arping_ip_list # 20: check arping ARP cache entries # # 30: watch for packet counter changes in promiscios mode # # If unsuccessfull in levels 18 and above, # the tests for higher check levels are run. # if_check () { local arp_list # always check link status first link_status="`get_link_status`" ocf_log debug "link_status: $link_status (1=up, 0=down)" if [ $link_status -eq 0 ]; then ocf_log notice "link_status: DOWN" return $OCF_NOT_RUNNING fi # if this is an infiniband device, try ibstatus script if [ -n "$OCF_RESKEY_infiniband_device" ]; then if infiniband_status; then return $OCF_SUCCESS fi ocf_log info "Infiniband device $OCF_RESKEY_infiniband_device is not available, check ibstatus for more information" return $OCF_NOT_RUNNING fi # if using link_status_only, skip RX count and arping related tests if ocf_is_true "$OCF_RESKEY_link_status_only"; then return $OCF_SUCCESS fi # watch for packet counter changes ocf_log debug "watch for packet counter changes" watch_pkt_counter if [ $? -eq 0 ]; then return $OCF_SUCCESS else ocf_log debug "No packets received during packet watch timeout" fi # check arping ARP cache entries ocf_log debug "check arping ARP cache entries" arp_list=`get_arp_list` for ip in `echo $arp_list`; do do_arping $ip && return $OCF_SUCCESS done # if we get here, the ethernet device is considered not running. # provide some logging information if [ -z "$arp_list" ]; then ocf_log info "No ARP cache entries found to arping" fi # watch for packet counter changes in promiscios mode # ocf_log debug "watch for packet counter changes in promiscios mode" # be sure switch off promiscios mode in any case # TODO: check first, wether promisc is already on and leave it untouched. # trap "$IP2UTIL link set dev $NIC promisc off; exit" INT TERM EXIT # $IP2UTIL link set dev $NIC promisc on # watch_pkt_counter && return $OCF_SUCCESS # $IP2UTIL link set dev $NIC promisc off # trap - INT TERM EXIT # looks like it's not working (for whatever reason) return $OCF_NOT_RUNNING } ####################################################################### if_usage() { cat < /dev/null` sleep $sleep_time 2> /dev/null runs=$(($runs + 1)) fi if [ $mon_rc -eq $OCF_SUCCESS -a $runs -ne 0 ]; then ocf_log info "Monitoring of $OCF_RESOURCE_INSTANCE recovered from error" fi done ocf_log debug "Monitoring return code: $mon_rc" if [ $mon_rc -eq $OCF_SUCCESS ]; then set_cib_value 1 attr_rc=$? else ocf_log err "Monitoring of $OCF_RESOURCE_INSTANCE failed." set_cib_value 0 attr_rc=$? fi ## The resource should not fail, if the interface is down. It should fail, if the update of the CIB variable has errors. ## To react on the interface failure you must use constraints based on the CIB variable value, not on the resource itself. exit $attr_rc } if_stop() { attrd_updater -D -n $ATTRNAME ha_pseudo_resource $OCF_RESOURCE_INSTANCE stop } if_start() { local rc ha_pseudo_resource $OCF_RESOURCE_INSTANCE start rc=$? if [ $rc -ne $OCF_SUCCESS ]; then ocf_exit_reason "Failure to create ethmonitor state file" return $rc fi # perform the first monitor during the start operation if_monitor return $? } if_validate() { check_binary $IP2UTIL check_binary arping if_init } case $__OCF_ACTION in meta-data) meta_data ;; usage|help) if_usage exit $OCF_SUCCESS ;; esac if_validate case $__OCF_ACTION in start) if_start exit $? ;; stop) if_stop exit $? ;; monitor|status) if_monitor exit $? ;; validate-all) exit $? ;; *) if_usage exit $OCF_ERR_UNIMPLEMENTED ;; esac diff --git a/heartbeat/garbd b/heartbeat/garbd index 950df76bb..50563fba3 100755 --- a/heartbeat/garbd +++ b/heartbeat/garbd @@ -1,417 +1,417 @@ #!/bin/sh # # Copyright (c) 2015 Damien Ciabrini # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # Further, this software is distributed without any warranty that it is # free of the rightful claim of any third person regarding infringement # or the like. Any license provided herein, whether implied or # otherwise, applies only to this software file. Patent licenses, if # any, provided herein do not apply to combinations of this program with # other software, or any other product whatsoever. # # You should have received a copy of the GNU General Public License # along with this program; if not, write the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. # ## # README. # # Resource agent for garbd, the Galera arbitrator # # You can use this agent if you run an even number of galera nodes, # and you want an additional node to avoid split-brain situations. # # garbd requires that a Galera cluster is running, so make sure to # add a proper ordering constraint to the cluster, e.g.: # # pcs constraint order galera-master then garbd # # If you add garbd to the cluster while Galera is not running, you # might want to disable it before setting up ordering constraint, e.g.: # # pcs resource create garbd garbd \ # wsrep_cluster_address=gcomm://node1:4567,node2:4567 \ # meta target-role=stopped # # Use location constraints to avoid running galera and garbd on # the same node, e.g.: # # pcs constraint colocation add garbd with galera-master -INFINITY # pcs constraint location garbd prefers node3=INFINITY # ## ####################################################################### # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ####################################################################### # Set default paramenter values OCF_RESKEY_binary_default="/usr/sbin/garbd" OCF_RESKEY_log_default="/var/log/garbd.log" OCF_RESKEY_pid_default="/var/run/garbd.pid" OCF_RESKEY_user_default="mysql" if [ "X${HOSTOS}" = "XOpenBSD" ];then OCF_RESKEY_group_default="_mysql" else OCF_RESKEY_group_default="mysql" fi : ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}} : ${OCF_RESKEY_log=${OCF_RESKEY_log_default}} : ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}} : ${OCF_RESKEY_user=${OCF_RESKEY_user_default}} : ${OCF_RESKEY_group=${OCF_RESKEY_group_default}} usage() { cat < 1.0 Resource script for managing Galera arbitrator. Manages a galera arbitrator instance Location of the Galera arbitrator binary garbd server binary User running the garbd process garbd user Group running garbd (for logfile permissions) garbd group The logfile to be used for garbd. Galera arbitrator log file The pidfile to be used for garbd. Galera arbitrator pidfile Additional parameters which are passed to garbd on startup. Additional parameters to pass to garbd The galera cluster address. This takes the form of: gcomm://node:port,node:port,node:port Unlike Galera servers, port is mandatory for garbd. Galera cluster address The group name of the Galera cluster to connect to. Galera cluster name END } garbd_start() { local rc local pid local start_wait local garbd_params garbd_status info rc=$? if [ $rc -eq $OCF_SUCCESS ]; then ocf_exit_reason "garbd started outside of the cluster's control" return $OCF_ERR_GENERIC; fi touch $OCF_RESKEY_log chown $OCF_RESKEY_user:$OCF_RESKEY_group $OCF_RESKEY_log chmod 0640 $OCF_RESKEY_log [ -x /sbin/restorecon ] && /sbin/restorecon $OCF_RESKEY_log garbd_params="--address=${OCF_RESKEY_wsrep_cluster_address} \ --group ${OCF_RESKEY_wsrep_cluster_name} \ --log ${OCF_RESKEY_log}" if [ ! -z "${OCF_RESKEY_options}" ]; then garbd_params="${garbd_params} --options=${OCF_RESKEY_options}" fi # garbd has no parameter to run as a specific user, # so we need to start it by our own means pid=$(su - -s /bin/sh $OCF_RESKEY_user -c "${OCF_RESKEY_binary} ${garbd_params} >/dev/null 2>&1 & echo \$!") # garbd doesn't create a pidfile either, so we create our own echo $pid > $OCF_RESKEY_pid if [ $? -ne 0 ]; then ocf_exit_reason "Cannot create pidfile for garbd at $OCF_RESKEY_pid (rc=$?), please check your installation" return $OCF_ERR_GENERIC fi # Spin waiting for garbd to connect to the cluster. # Let the CRM/LRM time us out if required. start_wait=1 while [ $start_wait -eq 1 ]; do garbd_monitor info rc=$? if [ $rc -eq $OCF_NOT_RUNNING ]; then ocf_exit_reason "garbd failed to start (pid=$pid), check logs in ${OCF_RESKEY_log}" return $OCF_ERR_GENERIC elif [ $rc -eq $OCF_SUCCESS ]; then start_wait=0 fi sleep 2 done ocf_log info "garbd connected to cluster \"${OCF_RESKEY_wsrep_cluster_name}\"" return $OCF_SUCCESS } garbd_status() { local loglevel=$1 local rc ocf_pidfile_status $OCF_RESKEY_pid rc=$? if [ $rc -eq 0 ]; then return $OCF_SUCCESS elif [ $rc -eq 2 ]; then return $OCF_NOT_RUNNING else # clean up if pidfile is stale if [ $rc -eq 1 ]; then ocf_log $loglevel "garbd not running: removing old PID file" rm -f $OCF_RESKEY_pid fi return $OCF_ERR_GENERIC fi } garbd_monitor() { local rc local pid local loglevel=$1 # Set loglevel to info during probe if ocf_is_probe; then loglevel="info" fi garbd_status $loglevel rc=$? # probe just wants to know if garbd is running or not - if [ ocf_is_probe -a $rc -ne $OCF_SUCCESS ]; then + if ocf_is_probe && [ $rc -ne $OCF_SUCCESS ]; then rc=$OCF_NOT_RUNNING fi # Consider garbd is working if it's connected to at least # one node in the galera cluster. # Note: a Galera node in Non-Primary state will be # stopped by the galera RA. So we can assume that # garbd will always be connected to the right partition if [ $rc -eq $OCF_SUCCESS ]; then pid=`cat $OCF_RESKEY_pid 2> /dev/null ` netstat -tnp 2>/dev/null | grep -s -q "ESTABLISHED.*${pid}/" if [ $? -ne 0 ]; then ocf_log $loglevel "garbd disconnected from cluster \"${OCF_RESKEY_wsrep_cluster_name}\"" rc=$OCF_ERR_GENERIC fi fi return $rc } garbd_stop() { local rc local pid if [ ! -f $OCF_RESKEY_pid ]; then ocf_log info "garbd is not running" return $OCF_SUCCESS fi pid=`cat $OCF_RESKEY_pid 2> /dev/null ` ocf_log info "stopping garbd" # make sure the process is stopped ocf_stop_processes TERM 10 $pid rc=$? if [ $rc -ne 0 ]; then return $OCF_ERR_GENERIC else rm -f $OCF_RESKEY_pid ocf_log info "garbd stopped" return $OCF_SUCCESS fi } garbd_validate() { if ! have_binary "$OCF_RESKEY_binary"; then ocf_exit_reason "Setup problem: couldn't find command: $OCF_RESKEY_binary" return $OCF_ERR_INSTALLED; fi if ! have_binary "netstat"; then ocf_exit_reason "Setup problem: couldn't find command: netstat" return $OCF_ERR_INSTALLED; fi if [ -z "$OCF_RESKEY_wsrep_cluster_address" ]; then ocf_exit_reason "garbd must be configured with a wsrep_cluster_address value." return $OCF_ERR_CONFIGURED fi # unlike galera RA, ports must be set in cluster address for garbd # https://github.com/codership/galera/issues/98 for node in $(echo "$OCF_RESKEY_wsrep_cluster_address" | sed 's/gcomm:\/\///g' | tr -d ' ' | tr -s ',' ' '); do echo $node | grep -s -q ':[1-9][0-9]*$' if [ $? -ne 0 ]; then ocf_exit_reason "wsrep_cluster_address must specify ports (gcomm://node1:port,node2:port)." return $OCF_ERR_CONFIGURED fi done # Ensure that the encryption method is set if garbd is configured # to use SSL. echo $OCF_RESKEY_options | grep -s -q -i -E '\bsocket.ssl_(key|cert)=' if [ $? -eq 0 ]; then echo $OCF_RESKEY_options | grep -s -q -i -E '\bsocket.ssl_cipher=' if [ $? -ne 0 ]; then ocf_exit_reason "option socket.ssl_cipher must be set if SSL is enabled." return $OCF_ERR_CONFIGURED fi fi if [ -z "$OCF_RESKEY_wsrep_cluster_name" ]; then ocf_exit_reason "garbd must be configured with a wsrep_cluster_name value." return $OCF_ERR_CONFIGURED fi if ! getent passwd $OCF_RESKEY_user >/dev/null 2>&1; then ocf_exit_reason "User $OCF_RESKEY_user doesn't exist" return $OCF_ERR_INSTALLED fi if ! getent group $OCF_RESKEY_group >/dev/null 2>&1; then ocf_exit_reason "Group $OCF_RESKEY_group doesn't exist" return $OCF_ERR_INSTALLED fi return $OCF_SUCCESS } case "$1" in meta-data) meta_data exit $OCF_SUCCESS;; usage|help) usage exit $OCF_SUCCESS;; esac garbd_validate rc=$? # trap configuration errors early, but don't block stop in such cases LSB_STATUS_STOPPED=3 if [ $rc -ne 0 ]; then case "$1" in stop) exit $OCF_SUCCESS;; status) exit $LSB_STATUS_STOPPED;; *) exit $rc;; esac fi # What kind of method was invoked? case "$1" in start) garbd_start;; stop) garbd_stop;; status) garbd_status err;; monitor) garbd_monitor err;; promote) garbd_promote;; demote) garbd_demote;; validate-all) exit $OCF_SUCCESS;; *) usage exit $OCF_ERR_UNIMPLEMENTED;; esac diff --git a/heartbeat/mysql-proxy b/heartbeat/mysql-proxy index 024e97e0d..4cb0bc9d9 100755 --- a/heartbeat/mysql-proxy +++ b/heartbeat/mysql-proxy @@ -1,719 +1,719 @@ #!/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"} 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 + if [ -n "$mysql_server_host" ]; then mysql_server_parameter="$mysql_server_parameter --host=$mysql_server_host" fi - if [ -n $mysql_server_port ]; then + 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