#!/usr/bin/env bash # A bash implementation of http://code.openark.org/blog/mysql/leader-election-using-mysql # Defaults quorum_alive_command='/bin/true' quorum_config='/etc/quorum.conf' quorum_db='quorum' quorum_db_command='/usr/bin/mysql' quorum_host='localhost' quorum_id=$(hostname -f) quorum_interval='20' quorum_notify_command='/usr/bin/echo alive status:${QUORUM_ALIVE_STATUS}, leader: ${QUORUM_LEADER}, my leader status: ${QUORUM_LEADER_STATUS}' quorum_password='quorum' quorum_table='service_election' quorum_user='quorum' # Override default config path from env if [[ "x${QUORUM_CONFIG}" != "x" ]]; then quorum_config="${QUORUM_CONFIG}" fi # Override default config with settings from config file if [[ -f "${quorum_config}" ]]; then . "${quorum_config}" fi # Override with env if [[ "x${QUORUM_ALIVE_COMMAND}" != "x" ]]; then quorum_alive_command=${QUORUM_ALIVE_COMMAND} fi if [[ "x${QUORUM_DB}" != "x" ]]; then quorum_db=${QUORUM_DB} fi if [[ "x${QUORUM_DB_COMMAND}" != "x" ]]; then quorum_db_command=${QUORUM_DB_COMMAND} fi if [[ "x${QUORUM_HOST}" != "x" ]]; then quorum_host=${QUORUM_HOST} fi if [[ "x${QUORUM_ID}" != "x" ]]; then quorum_id=${QUORUM_ID} fi if [[ "x${QUORUM_INTERVAL}" != "x" ]]; then quorum_interval=${QUORUM_INTERVAL} fi if [[ "x${QUORUM_NOTIFY_COMMAND}" != "x" ]]; then quorum_notify_command=${QUORUM_NOTIFY_COMMAND} fi if [[ "x${QUORUM_PASSWORD}" != "x" ]]; then quorum_password=${QUORUM_PASSWORD} fi if [[ "x${QUORUM_TABLE}" != "x" ]]; then quorum_table=${QUORUM_TABLE} fi if [[ "x${QUORUM_USER}" != "x" ]]; then quorum_user=${QUORUM_USER} fi # MySQL command quorum_db_command="${quorum_db_command} --database=${quorum_db} --user ${quorum_user} --password ${quorum_password}" # Queries create_table_query='CREATE TABLE ${quorum_table} ( anchor tinyint(3) unsigned NOT NULL, service_id varchar(128) NOT NULL, last_seen_active timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (anchor) ) ENGINE=InnoDB' table_exists_query="SELECT * FROM information_schema.tables WHERE table_schema = '${quorum_db}' AND table_name = '${quorum_table}' LIMIT 1" election_query="insert ignore into ${quorum_table} ( anchor, service_id, last_seen_active ) values ( 1, '${quorum_id}', now() ) on duplicate key update service_id = if(last_seen_active < now() - interval ${quorum_interval} second, values(service_id), service_id), last_seen_active = if(service_id = values(service_id), values(last_seen_active), last_seen_active)" is_leader_query="select count(*) as is_leader from ${quorum_table} where anchor=1 and service_id='${quorum_id}'" who_is_leader_query="select max(service_id) as leader from ${quorum_table} where anchor=1" # Set up table if it does not exist ${quorum_db_command} -e "${table_exists_query}" >/dev/null 2>&1 if [[ ${?} -ne 0 ]]; then ${quorum_db_command} -e "${create_table_query}" >/dev/null 2>&1 fi # Run the algorithm ${quorum_alive_command} >/dev/null 2>&1 alive_status=${?} if [[ ${alive_status} -eq 0 ]]; then ${quorum_db_command} -e "${election_query}" >/dev/null 2>&1 fi leader_status=$(${quorum_db_command} -e "${is_leader_query}") leader=$(${quorum_db_command} -e "${who_is_leader_query}") QUORUM_ALIVE_STATUS=${alive_status} QUORUM_LEADER=${leader} QUORUM_LEADER_STATUS=${leader_status} eval ${quorum_notify_command} exit ${alive_status}