Hello,
this is a cleaned up revision of my patch to the mysql RA.
I'm changing only 2 commands from the old RA simply to remove one unnecessary 
echo to the mysql command.

I didn't split it into multiple patches, yet, since I'm sure that there is 
more work to be done. After I'm finished I'll publish it as several sequential 
patches.

Best regards,
Marian Marinov
--- mysql	2010-02-24 01:49:31.000000000 +0200
+++ /home/hackman/Projects/linux-ha/mysql-replica	2010-02-24 02:05:43.000000000 +0200
@@ -11,6 +10,7 @@
 # Author:	Andrew Beekhof 		: Cleanup and import
 # Author:	Sebastian Reitenbach    : add OpenBSD defaults, more cleanup
 # Author:  Narayan Newton      : Add Gentoo/Debian defaults
+# Author:	Marian Marinov		: Add replication capabilities
 #
 # Support:	[email protected]
 # License:	GNU General Public License (GPL)
@@ -35,16 +35,21 @@
 #   OCF_RESKEY_log
 #   OCF_RESKEY_pid
 #   OCF_RESKEY_socket
+#   OCF_RESKEY_replication_user
+#   OCF_RESKEY_replication_passwd
 #######################################################################
 # Initialization:
 
 : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat}
 . ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs
+VERSION=0.18
 
 #######################################################################
 
 # Fill in some defaults if no values are specified
 HOSTOS=`uname`
+HOSTNAME=`hostname`
+
 if [ "X${HOSTOS}" = "XOpenBSD" ];then
 OCF_RESKEY_binary_default="/usr/local/bin/mysqld_safe"
 OCF_RESKEY_config_default="/etc/my.cnf"
@@ -54,10 +59,6 @@ OCF_RESKEY_group_default="_mysql"
 OCF_RESKEY_log_default="/var/log/mysqld.log"
 OCF_RESKEY_pid_default="/var/mysql/mysqld.pid"
 OCF_RESKEY_socket_default="/var/run/mysql/mysql.sock"
-OCF_RESKEY_test_user_default="root"
-OCF_RESKEY_test_table_default="mysql.user"
-OCF_RESKEY_test_passwd_default=""
-OCF_RESKEY_enable_creation_default=0
 OCF_RESKEY_additional_parameters_default=""
 else
 OCF_RESKEY_binary_default="/usr/bin/safe_mysqld"
@@ -68,12 +69,14 @@ OCF_RESKEY_group_default="mysql"
 OCF_RESKEY_log_default="/var/log/mysqld.log"
 OCF_RESKEY_pid_default="/var/run/mysql/mysqld.pid"
 OCF_RESKEY_socket_default="/var/lib/mysql/mysql.sock"
+OCF_RESKEY_additional_parameters_default=""
+fi
+OCF_RESKEY_enable_creation_default=0
 OCF_RESKEY_test_user_default="root"
 OCF_RESKEY_test_table_default="mysql.user"
 OCF_RESKEY_test_passwd_default=""
-OCF_RESKEY_enable_creation_default=0
-OCF_RESKEY_additional_parameters_default=""
-fi
+OCF_RESKEY_replication_user_default=""
+OCF_RESKEY_replication_passwd_default=""
 
 : ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
 MYSQL_BINDIR=`dirname ${OCF_RESKEY_binary}`
@@ -95,9 +97,12 @@ MYSQL_BINDIR=`dirname ${OCF_RESKEY_binar
 : ${OCF_RESKEY_enable_creation=${OCF_RESKEY_enable_creation_default}}
 : ${OCF_RESKEY_additional_parameters=${OCF_RESKEY_additional_parameters_default}}
 
+: ${OCF_RESKEY_replication_user=${OCF_RESKEY_replication_user_default}}
+: ${OCF_RESKEY_replication_passwd=${OCF_RESKEY_replication_passwd_default}}
+
 usage() {
   cat <<UEND
-	usage: $0 (start|stop|validate-all|meta-data|monitor)
+	usage: $0 (start|stop|validate-all|meta-data|monitor|notify|promote|demote)
 
 	$0 manages a MySQL Database as an HA resource.
 
@@ -105,6 +110,9 @@ usage() {
 	The 'stop' operation stops the database.
 	The 'status' operation reports whether the database is running
 	The 'monitor' operation reports whether the database seems to be working
+	The 'promote' operation makes this mysql server run as master
+	The 'demote' operation makes this mysql server run as slave
+	The 'notify' operation is used for post execution
 	The 'validate-all' operation reports whether the parameters are valid
 
 UEND
@@ -115,7 +123,7 @@ meta_data() {
 <?xml version="1.0"?>
 <!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
 <resource-agent name="mysql">
-<version>1.0</version>
+<version>1.1</version>
 
 <longdesc lang="en">
 Resource script for MySQL. 
@@ -230,6 +238,22 @@ Additional parameters which are passed t
 <content type="string" default="${OCF_RESKEY_additional_parameters_default}"/>
 </parameter>
 
+<parameter name="replication_user" unique="0" required="0">
+<longdesc lang="en">
+MySQL replication user. Used for replication client and slave.
+</longdesc>
+<shortdesc lang="en">MySQL replication user</shortdesc>
+<content type="string" default="${OCF_RESKEY_replication_user_default}" />
+</parameter>
+
+<parameter name="replication_passwd" unique="0" required="0">
+<longdesc lang="en">
+MySQL replication password. Used for replication client and slave.
+</longdesc>
+<shortdesc lang="en">MySQL replication user password</shortdesc>
+<content type="string" default="${OCF_RESKEY_replication_passwd_default}" />
+</parameter>
+
 </parameters>
 
 <actions>
@@ -237,6 +261,11 @@ Additional parameters which are passed t
 <action name="stop" timeout="120" />
 <action name="status" timeout="60" />
 <action name="monitor" depth="0" timeout="30" interval="10" />
+<action name="monitor" depth="0"  timeout="20" interval="20" start-delay="0" role="Slave" />
+<action name="monitor" depth="0"  timeout="20" interval="10" start-delay="0" role="Master" />
+<action name="notify" timeout="90" />
+<action name="promote" timeout="120" />
+<action name="demote" timeout="120" />
 <action name="validate-all" timeout="5" />
 <action name="meta-data" timeout="5" />
 </actions>
@@ -272,9 +301,59 @@ mysql_validate() {
 	ocf_log err "Group $OCF_RESKEY_group doesn't exist";
 	return $OCF_ERR_INSTALLED;
     fi
+
+	if [ ! -z "${OCF_RESKEY_CRM_meta_master_max}" ] && [ "${OCF_RESKEY_CRM_meta_master_max}" > 0 ]; then
+    	if [ -z "$OCF_RESKEY_replication_user" ] || [ -z "$OCF_RESKEY_replication_passwd" ]; then
+			ocf_log err "Missing replication username or password"
+			exit $OCF_ERR_CONFIGURED
+    	fi
+    fi
     true
 }
 
+is_slave() {
+	slave_info=($(mysql \
+		--user=$OCF_RESKEY_replication_user \
+		--password=$OCF_RESKEY_replication_passwd \
+		--socket=$OCF_RESKEY_socket -O connect_timeout=1 \
+		-e 'SHOW SLAVE STATUS\G'|awk '/Running/ || /Master_[UHP]/{print $2}'))
+
+	if [ "$?" != 0 ]; then
+		ocf_log err "Unable to get local slave status"
+		return 1
+	fi
+
+	if [ -z "${slave_info[*]}" ]; then
+		# no slave configuration, can not be slave
+		return 1;
+	fi
+
+	if [ -z "${slave_info[3]}" ] || [ -z "${slave_info[4]}" ] || [ -z "${slave_info[0]}" ] || [ -z "${slave_info[0]}" ]; then
+		ocf_log err "Unable to get slave status"
+		return 1
+	fi
+
+	if [ $# == 1 ]; then
+		if [ "${slave_info[3]}" == 'Yes' ] &&
+			[ "${slave_info[4]}" == 'Yes' ] &&
+			[ "${slave_info[1]}" == "$OCF_RESKEY_replication_user" ] &&
+			( grep "${slave_info[0]}" /etc/hosts > /dev/null ); then
+			# machine is slave
+			return 0;
+		fi
+	else
+		if [ "${slave_info[3]}" == 'Yes' ] || [ "${slave_info[4]}" == 'Yes' ]; then
+			if [ "${slave_info[1]}" == "$OCF_RESKEY_replication_user" ] && ( grep "${slave_info[0]}" /etc/hosts > /dev/null ); then
+				# machine is slave
+				return 0;
+			fi
+		fi
+	fi
+
+	# machine is not slave
+	return 1;
+}
+
 mysql_status() {
 	if [ ! -e $OCF_RESKEY_pid ]; then
 		ocf_log debug "MySQL is not running"
@@ -301,14 +380,37 @@ mysql_monitor() {
     mysql_status
     rc=$?
 
-    if [ $OCF_CHECK_LEVEL = 0 -o $rc != 0 ]; then
+	if ! is_slave; then
+		# if the check came from probe
+		if [ "$OCF_RESKEY_CRM_meta_interval" = "0" ]; then
+			return $OCF_RUNNING_MASTER;
+		fi
+		# if the check requires a master/slave status and this is the Master node
+		if [ "$OCF_RESKEY_CRM_meta_role" == "Master" ]; then
+			return $OCF_RUNNING_MASTER
+		fi
+	fi
+
+	if [ $OCF_CHECK_LEVEL == 0 ]; then
 	return $rc
     fi
 
+	if [ ! -z "${OCF_RESKEY_CRM_meta_master_max}" ] &&
+		[ "${OCF_RESKEY_CRM_meta_master_max}" > 0 ] &&
+		[ "$OCF_RESKEY_CRM_meta_role" == "Slave" ] &&
+		is_slave 1; then
+		return $OCF_SUCCESS
+	fi
+
     # Do a detailed status check
-    buf=`echo "SELECT * FROM $OCF_RESKEY_test_table" | mysql --user=$OCF_RESKEY_test_user --password=$OCF_RESKEY_test_passwd --socket=$OCF_RESKEY_socket -O connect_timeout=1 2>&1`
+    buf=$(mysql --user=$OCF_RESKEY_test_user \
+		--password=$OCF_RESKEY_test_passwd \
+		--socket=$OCF_RESKEY_socket \
+		-O connect_timeout=1 \
+		-e "SELECT * FROM $OCF_RESKEY_test_table" 2>&1)
     rc=$?
-    if [ ! $rc -eq 0 ]; then
+
+    if [ $rc -ne 0 ]; then
 	ocf_log err "MySQL $test_table monitor failed:";
 	if [ ! -z "$buf" ]; then ocf_log err $buf; fi
 	return $OCF_ERR_GENERIC;
@@ -319,12 +421,8 @@ mysql_monitor() {
 }
 
 mysql_start() {
+	mysql_validate
     mysql_status
-    if [ $? = $OCF_SUCCESS ]; then
-	ocf_log info "MySQL already running"
-	return $OCF_SUCCESS
-    fi
-
     touch $OCF_RESKEY_log
     chown $OCF_RESKEY_user:$OCF_RESKEY_group $OCF_RESKEY_log
     chmod 0640 $OCF_RESKEY_log
@@ -366,7 +464,11 @@ mysql_start() {
     #chown -R $OCF_RESKEY_user $OCF_RESKEY_datadir
     #chgrp -R $OCF_RESKEY_group $OCF_RESKEY_datadir
 
-    ${OCF_RESKEY_binary}  --defaults-file=$OCF_RESKEY_config --pid-file=$OCF_RESKEY_pid --socket=$OCF_RESKEY_socket --datadir=$OCF_RESKEY_datadir --user=$OCF_RESKEY_user $OCF_RESKEY_additional_parameters >/dev/null &
+    ${OCF_RESKEY_binary} --defaults-file=$OCF_RESKEY_config \
+		--pid-file=$OCF_RESKEY_pid \
+		--socket=$OCF_RESKEY_socket \
+		--datadir=$OCF_RESKEY_datadir \
+		--user=$OCF_RESKEY_user $OCF_RESKEY_additional_parameters >/dev/null 2>&1 &
     rc=$?
     
     if [ $rc != 0 ]; then
@@ -395,6 +496,7 @@ mysql_start() {
 }
 
 mysql_stop() {
+	mysql_validate
     if [ ! -f $OCF_RESKEY_pid ]; then
 	ocf_log info "MySQL is not running"
         return $OCF_SUCCESS
@@ -408,60 +510,134 @@ mysql_stop() {
 	return $OCF_ERR_GENERIC
     fi
 
-	# stop waiting
-	shutdown_timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000)-5))
-	count=0
-	while [ $count -lt $shutdown_timeout ]
-	do
+	stop_wait=1
+	while [ $stop_wait = 1 ]; do
 		mysql_status
 		rc=$?
 		if [ $rc = $OCF_NOT_RUNNING ]; then
-			break
+			stop_wait=0
 		fi
-		count=`expr $count + 1`
 		sleep 1
-		ocf_log debug "MySQL still hasn't stopped yet. Waiting..."
 	done
 
-	mysql_status
-	if [ $? != $OCF_NOT_RUNNING ]; then
-		ocf_log info "MySQL failed to stop after ${shutdown_timeout}s using SIGTERM. Trying SIGKILL..."
-		/bin/kill -KILL $pid > /dev/null
-	fi
-
     ocf_log info "MySQL stopped";
     rm -f /var/lock/subsys/mysqld
     rm -f $OCF_RESKEY_socket
     return $OCF_SUCCESS
 }
 
-case "$1" in
-  meta-data)	meta_data
-		exit $OCF_SUCCESS;;
-  usage|help)	usage
-		exit $OCF_SUCCESS;;
-esac
+mysql_promote() {
+	if ( ! mysql_status ); then
+		return $OCF_NOT_RUNNING
+	fi
+	if [ "$OCF_RESKEY_CRM_meta_notify_promote_uname" != "$HOSTNAME " ]; then
+		return $OCF_ERR_GENERIC
+	fi
+	if is_slave; then
+		mysql --socket=$OCF_RESKEY_socket -O connect_timeout=1 -e 'STOP SLAVE'
+	fi
+	return $OCF_SUCCESS
+}
 
-mysql_validate
-rc=$?
-LSB_STATUS_STOPPED=3
-if [ $rc -ne 0 ]; then
-	case "$1" in
-		stop) exit $OCF_SUCCESS;;
-		monitor) exit $OCF_NOT_RUNNING;;
-		status) exit $LSB_STATUS_STOPPED;;
-		*) exit $rc;;
-	esac
+mysql_demote() {
+	search_uname=''
+	if [[ "$OCF_RESKEY_CRM_meta_notify_master_uname" =~ "^\s*$" ]] &&
+		[[ "$OCF_RESKEY_CRM_meta_notify_promote_uname" =~ "^\s*$" ]]; then
+		echo "No master or promote uname found" >> /tmp/replica.log
+		return $OCF_ERR_GENERIC
+	fi
+	if [ "$OCF_RESKEY_CRM_meta_notify_promote_uname" == "$HOSTNAME " ]; then
+		echo "Should not connect to my self(promote)" >> /tmp/replica.log
+		return $OCF_ERR_GENERIC
+	else
+		search_uname=$OCF_RESKEY_CRM_meta_notify_promote_uname
+	fi
+	if [ "$OCF_RESKEY_CRM_meta_notify_master_uname" == "$HOSTNAME " ]; then
+		echo "Should not connect to my self(master)" >> /tmp/replica.log
+		return $OCF_ERR_GENERIC
+	else
+		search_uname=$OCF_RESKEY_CRM_meta_notify_master_uname
+	fi
+
+	if ( ! mysql_status ); then
+		return $OCF_NOT_RUNNING
 fi
+	if [ $# != 1 ] && [ "$OCF_RESKEY_CRM_meta_notify_demote_uname" != "$HOSTNAME " ]; then
+		return $OCF_ERR_GENERIC
+	fi
+	if is_slave 1; then
+		return $OCF_SUCCESS
+	else
+		if [ -z "$search_uname" ]; then	return $OCF_ERR_GENERIC; fi
+		master_host=$(grep $OCF_RESKEY_CRM_meta_notify_master_uname /etc/hosts|awk '{print $1;exit}')
+		if [ -z "$master_host" ]; then
+			ocf_log err "Unable to get IP address of host $OCF_RESKEY_CRM_meta_notify_master_uname"
+	       	return $OCF_ERR_GENERIC;
+		fi
+		master_info=($(mysql \
+			--password=$OCF_RESKEY_replication_passwd \
+       		--user=$OCF_RESKEY_replication_user \
+       		-h $master_host \
+       		-O connect_timeout=1 \
+	       	-e 'SHOW MASTER STATUS\G'|awk '/File/||/Position/{print $2}'))
+		if [ -z "${master_info[0]}" ] || [ -z "${master_info[1]}" ]; then
+			ocf_log err "Empty master file or master position"
+	       	return $OCF_ERR_GENERIC;
+		fi
+		mysql --socket=$OCF_RESKEY_socket -O connect_timeout=1 -e 'STOP SLAVE';
+		mysql --socket=$OCF_RESKEY_socket -O connect_timeout=1 \
+			-e "CHANGE MASTER TO MASTER_HOST='$master_host', \
+				MASTER_USER='$OCF_RESKEY_replication_user', \
+				MASTER_PASSWORD='$OCF_RESKEY_replication_passwd', \
+				MASTER_PORT=3306, \
+				MASTER_LOG_FILE='${master_info[0]}', \
+				MASTER_LOG_POS=${master_info[1]}, \
+				MASTER_CONNECT_RETRY=4"
+		mysql --socket=$OCF_RESKEY_socket -O connect_timeout=1 -e 'START SLAVE';
+		if [ $? == $OCF_ERR_GENERIC ]; then
+			return $OCF_ERR_GENERIC
+		fi
+	fi
+	if is_slave 1; then
+		return $OCF_SUCCESS
+	else
+		return $OCF_ERR_GENERIC
+	fi
+}
+
+mysql_notify() {
+	if [ "$OCF_RESKEY_CRM_meta_notify_type" != 'post' ]; then
+		return $OCF_SUCCESS
+	fi
+	case "$OCF_RESKEY_CRM_meta_notify_operation" in
+		'promote')
+			if [ "$OCF_RESKEY_CRM_meta_notify_promote_uname" != "$HOSTNAME " ] &&
+ 				! is_slave 1; then
+				mysql_demote 1
+			fi
+		;;
+		'demote')
+			if [ "$OCF_RESKEY_CRM_meta_notify_promote_uname" == "$HOSTNAME " ] &&
+				! is_slave 1; then
+				mysql_demote 1
+			fi
+		;;
+		*) return $OCF_SUCCESS ;;
+	esac
+
+}
 
 # What kind of method was invoked?
 case "$1" in
   start)	mysql_start;;
   stop)		mysql_stop;;
   status)	mysql_status;;
+  promote)	mysql_promote;;
+  demote)	mysql_demote;;
   monitor)	mysql_monitor;;
-  validate-all)	exit $OCF_SUCCESS;;
-
- *)		usage
-		exit $OCF_ERR_UNIMPLEMENTED;;
+  notify)	mysql_notify;;
+  meta-data) meta_data;;
+  validate-all)	mysql_validate;;
+  usage|help) usage; exit $OCF_SUCCESS;;
+ *)	usage; exit $OCF_ERR_UNIMPLEMENTED;;
 esac

Attachment: signature.asc
Description: This is a digitally signed message part.

_______________________________________________
Linux-HA mailing list
[email protected]
http://lists.linux-ha.org/mailman/listinfo/linux-ha
See also: http://linux-ha.org/ReportingProblems

Reply via email to