@@ -9,155 +9,74 @@ log() {
99 echo " {\" time\" :\" ${date} \" , \" message\" : \" ${message} \" }"
1010}
1111
12- MYSQL_PORT=3306
13- MYSQLX_PORT=33060
14- MYSQL_ADMIN_PORT=33062
15- primary_mysql_node=' '
16- primary_mysql_host=' '
17-
18- function main() {
19- log " Running $0 "
20-
21- NODE_LIST=()
22- NODE_LIST_REPL=()
23- NODE_LIST_MYSQLX=()
24- NODE_LIST_ADMIN=()
25-
26- SERVER_OPTIONS=${HA_SERVER_OPTIONS:- ' resolvers kubernetes inter 10000 rise 1 fall 2 check weight 1' }
27- send_proxy=' '
28- path_to_haproxy_cfg=' /etc/haproxy/mysql'
29- if [[ ${IS_PROXY_PROTOCOL} == " yes" ]]; then
30- send_proxy=' send-proxy-v2'
12+ SOCK=" ${HA_STATS_SOCKET:-/ etc/ haproxy/ mysql/ haproxy.sock} "
13+ MAX_SLOTS=" ${HA_MAX_SLOTS:- 9} "
14+ path_to_haproxy_cfg=' /etc/haproxy/mysql'
15+ BACKENDS=' mysql-primary mysql-replicas mysql-x mysql-admin'
16+
17+ haproxy_socket_cmd () {
18+ local cmd=$1
19+ local out
20+
21+ out=$( echo " $cmd " | socat -t 5 stdio " $SOCK " | tr -d ' \n' )
22+ if [ -n " $out " ]; then
23+ log " '${cmd} ' -> ${out} "
3124 fi
25+ return 0
26+ }
3227
33- while read mysql_host; do
34- if [ -z " $mysql_host " ]; then
35- log ' Could not find PEERS ...'
36- exit 0
37- fi
28+ main () {
29+ log " Running $0 "
3830
39- node_name= $( echo " $mysql_host " | cut -d . -f -1 )
40- if /opt/percona/haproxy_check_primary.sh ' ' ' ' " $ mysql_host" ; then
41- primary_mysql_host= " $ mysql_host"
42- primary_mysql_node= " server ${node_name} ${ mysql_host} : ${MYSQL_PORT} ${send_proxy} ${SERVER_OPTIONS} on-marked-up shutdown-backup-sessions "
43- continue
31+ local peers=( )
32+ local mysql_host
33+ while read -r mysql_host; do
34+ if [ -n " $ mysql_host" ] ; then
35+ peers+=( " $mysql_host " )
4436 fi
45-
46- NODE_LIST_REPL+=(" server ${node_name} ${mysql_host} :${MYSQL_PORT} ${send_proxy} ${SERVER_OPTIONS} " )
47- NODE_LIST+=(" server ${node_name} ${mysql_host} :${MYSQL_PORT} ${send_proxy} ${SERVER_OPTIONS} backup" )
48- NODE_LIST_ADMIN+=(" server ${node_name} ${mysql_host} :${MYSQL_ADMIN_PORT} ${SERVER_OPTIONS} backup" )
49- NODE_LIST_MYSQLX+=(" server ${node_name} ${mysql_host} :${MYSQLX_PORT} ${send_proxy} ${SERVER_OPTIONS} backup" )
5037 done
5138
52- # mysql-x and mysql-admin replicas run the same external check against the
53- # same admin port as mysql-replicas, so mirror the state with 'track'
54- # instead of running duplicate checks. Only replicas can track: the primary
55- # node is not present in the mysql-replicas backend and keeps its own check.
56- if [ " ${# NODE_LIST_REPL[@]} " -gt 1 ]; then
57- for i in " ${! NODE_LIST_ADMIN[@]} " ; do
58- node_name=$( echo " ${NODE_LIST_ADMIN[$i]} " | cut -d ' ' -f 2)
59- NODE_LIST_ADMIN[$i ]=" $( echo " ${NODE_LIST_ADMIN[$i]} " | sed ' s/ check / /' ) track mysql-replicas/${node_name} "
60- done
61- for i in " ${! NODE_LIST_MYSQLX[@]} " ; do
62- node_name=$( echo " ${NODE_LIST_MYSQLX[$i]} " | cut -d ' ' -f 2)
63- NODE_LIST_MYSQLX[$i ]=" $( echo " ${NODE_LIST_MYSQLX[$i]} " | sed ' s/ check / /' ) track mysql-replicas/${node_name} "
64- done
39+ if [ " ${# peers[@]} " -eq 0 ]; then
40+ log ' Could not find PEERS ...'
41+ exit 0
6542 fi
6643
67- if [ -n " $primary_mysql_host " ]; then
68- if [[ " ${# NODE_LIST[@]} " -ne 0 ]]; then
69- NODE_LIST=(" $primary_mysql_node " " $( printf ' %s\n' " ${NODE_LIST[@]} " | sort --version-sort -r | uniq) " )
70- NODE_LIST_ADMIN=(" $primary_mysql_node " " $( printf ' %s\n' " ${NODE_LIST_ADMIN[@]} " | sort --version-sort -r | uniq) " )
71- NODE_LIST_MYSQLX=(" $primary_mysql_node " " $( printf ' %s\n' " ${NODE_LIST_MYSQLX[@]} " | sort --version-sort -r | uniq) " )
72- else
73- NODE_LIST=(" $primary_mysql_node " )
74- NODE_LIST_ADMIN=(" $primary_mysql_node " )
75- NODE_LIST_MYSQLX=(" $primary_mysql_node " )
76- fi
77- else
78- if [[ " ${# NODE_LIST[@]} " -ne 0 ]]; then
79- NODE_LIST=(" $( printf ' %s\n' " ${NODE_LIST[@]} " | sort --version-sort -r | uniq) " )
80- NODE_LIST_ADMIN=(" $( printf ' %s\n' " ${NODE_LIST_ADMIN[@]} " | sort --version-sort -r | uniq) " )
81- NODE_LIST_MYSQLX=(" $( printf ' %s\n' " ${NODE_LIST_MYSQLX[@]} " | sort --version-sort -r | uniq) " )
82- fi
83- fi
84-
85-
86- echo " ${# NODE_LIST_REPL[@]} " > $path_to_haproxy_cfg /AVAILABLE_NODES
87- log " number of available nodes are ${# NODE_LIST_REPL[@]} "
44+ # stable slot assignment: version-sort == pod ordinal order for statefulsets
45+ mapfile -t peers < <( printf ' %s\n' " ${peers[@]} " | sort --version-sort | uniq)
8846
89- haproxy_check_script= ' haproxy_check_primary.sh '
90- if [ " ${# NODE_LIST_REPL [@]} " -gt 1 ] ; then
91- haproxy_check_script= ' haproxy_check_replicas.sh '
47+ if [ " ${ # peers[@]} " -gt " $MAX_SLOTS " ] ; then
48+ log " ERROR: ${# peers [@]} peers but only ${MAX_SLOTS} slots; raise HA_MAX_SLOTS "
49+ exit 1
9250 fi
9351
94- cat << -EOF >"$path_to_haproxy_cfg /haproxy.cfg"
95- backend mysql-primary
96- mode tcp
97- option srvtcpka
98- balance roundrobin
99- option external-check
100- external-check command /opt/percona/haproxy_check_primary.sh
101- EOF
102-
103- (
104- IFS=$' \n '
105- echo " ${NODE_LIST[*]} "
106- ) >> " $path_to_haproxy_cfg /haproxy.cfg"
107-
108- cat << -EOF >>"$path_to_haproxy_cfg /haproxy.cfg"
109- backend mysql-replicas
110- mode tcp
111- option srvtcpka
112- balance roundrobin
113- option external-check
114- external-check command /opt/percona/haproxy_check_replicas.sh
115- EOF
116-
117- (
118- IFS=$' \n '
119- echo " ${NODE_LIST_REPL[*]} "
120- ) >> " $path_to_haproxy_cfg /haproxy.cfg"
121-
122- cat << -EOF >>"$path_to_haproxy_cfg /haproxy.cfg"
123- backend mysql-x
124- mode tcp
125- option srvtcpka
126- balance roundrobin
127- option external-check
128- external-check command /opt/percona/$haproxy_check_script
129- EOF
130-
131- (
132- IFS=$' \n '
133- echo " ${NODE_LIST_MYSQLX[*]} "
134- ) >> " $path_to_haproxy_cfg /haproxy.cfg"
135-
136- cat << -EOF >>"$path_to_haproxy_cfg /haproxy.cfg"
137- backend mysql-admin
138- mode tcp
139- option srvtcpka
140- balance roundrobin
141- option external-check
142- external-check command /opt/percona/$haproxy_check_script
143- EOF
144- (
145- IFS=$' \n '
146- echo " ${NODE_LIST_ADMIN[*]} "
147- ) >> " $path_to_haproxy_cfg /haproxy.cfg"
148-
149- path_to_custom_global_cnf=' /etc/haproxy-custom'
150- if [ -f " $path_to_custom_global_cnf /haproxy-global.cfg" ]; then
151- haproxy -c -f " $path_to_custom_global_cnf /haproxy-global.cfg" -f $path_to_haproxy_cfg /haproxy.cfg
152- fi
52+ # replica count for the check scripts: peers minus primary (if one exists)
53+ local n_replicas=${# peers[@]}
54+ for mysql_host in " ${peers[@]} " ; do
55+ if /opt/percona/haproxy_check_primary.sh ' ' ' ' " $mysql_host " ; then
56+ n_replicas=$(( n_replicas - 1 ))
57+ break
58+ fi
59+ done
15360
154- haproxy -c -f /opt/percona/haproxy-global.cfg -f $path_to_haproxy_cfg /haproxy.cfg
61+ echo " $n_replicas " > " $path_to_haproxy_cfg /AVAILABLE_NODES"
62+ log " number of available nodes are ${n_replicas} "
15563
156- # TODO: Can we do something for maintenance mode?
157- if [ -S " $path_to_haproxy_cfg /haproxy-main.sock" ]; then
158- log " reload | socat stdio $path_to_haproxy_cfg /haproxy-main.sock"
159- echo ' reload' | socat stdio " $path_to_haproxy_cfg /haproxy-main.sock"
160- fi
64+ local be i
65+ for be in $BACKENDS ; do
66+ i=0
67+ for mysql_host in " ${peers[@]} " ; do
68+ haproxy_socket_cmd " set server ${be} /${CLUSTER_NAME} -mysql-${i} fqdn ${mysql_host} "
69+ haproxy_socket_cmd " set server ${be} /${CLUSTER_NAME} -mysql-${i} state ready"
70+ i=$(( i + 1 ))
71+ done
72+
73+ # park unused slots and kill any sessions still pinned to them
74+ while [ " $i " -lt " $MAX_SLOTS " ]; do
75+ haproxy_socket_cmd " set server ${be} /${CLUSTER_NAME} -mysql-${i} state maint"
76+ haproxy_socket_cmd " shutdown sessions server ${be} /${CLUSTER_NAME} -mysql-${i} "
77+ i=$(( i + 1 ))
78+ done
79+ done
16180}
16281
16382main
0 commit comments