Logoj0ke.net Open Build Service > Projects > internetx:mysql5 > proxysql > proxysql_node_monitor
Sign Up | Log In

File proxysql_node_monitor of Package proxysql

 
1
#!/bin/bash
2
# This script will assist to setup Percona XtraDB cluster ProxySQL monitoring script.
3
#####################################################################################
4
5
debug=0
6
7
ERR_FILE="${3:-/dev/null}"
8
if [ -f /etc/proxysql-admin.cnf ]; then
9
  source /etc/proxysql-admin.cnf
10
else
11
  echo "`date` Assert! proxysql-admin configuration file :/etc/proxysql-admin.cnf does not exists, Terminating!" >> $ERR_FILE
12
  exit 1
13
fi
14
15
if [[ -z "$PROXYSQL_DATADIR" ]]; then
16
  PROXYSQL_DATADIR='/var/lib/proxysql'
17
fi
18
19
WRITE_HOSTGROUP_ID="${1:-0}"
20
READ_HOSTGROUP_ID="${2:-0}"
21
SLAVEREAD_HOSTGROUP_ID=$READ_HOSTGROUP_ID
22
if [ $SLAVEREAD_HOSTGROUP_ID -eq $WRITE_HOSTGROUP_ID ];then
23
  let SLAVEREAD_HOSTGROUP_ID+=1
24
fi
25
26
CHECK_STATUS=0
27
SLAVE_SECONDS_BEHIND=3600 #How far behind can a slave be before its put into OFFLINE_SOFT state
28
CLUSTER_TIMEOUT=3 # Maximum time to wait for cluster status
29
30
proxysql_exec() {
31
  query=$1
32
    printf "[client]\nuser=${PROXYSQL_USERNAME}\npassword=${PROXYSQL_PASSWORD}\nhost=${PROXYSQL_HOSTNAME}\nport=${PROXYSQL_PORT}\n" | \
33
      mysql --defaults-file=/dev/stdin --protocol=tcp -Bse "${query}" 2>/dev/null
34
}
35
36
if [ $debug -eq 1 ];then echo "`date` DEBUG MODE: $MODE" >> $ERR_FILE;fi
37
38
if [ $debug -eq 1 ];then echo "`date` DEBUG check mode name from proxysql data directory " >> $ERR_FILE;fi
39
CLUSTER_NAME=$(proxysql_exec "select comment from scheduler where arg1=$WRITE_HOSTGROUP_ID")
40
if [ -f ${PROXYSQL_DATADIR}/${CLUSTER_NAME}_mode ] ; then
41
  MODE=$(cat ${PROXYSQL_DATADIR}/${CLUSTER_NAME}_mode)
42
fi
43
44
if [ "$MODE" == "loadbal" ]; then
45
  MODE_COMMENT="READWRITE"
46
  WRITE_WEIGHT="1000"
47
else
48
  MODE_COMMENT="READ"
49
  WRITE_WEIGHT="1000000"
50
fi
51
52
check_cmd(){
53
  MPID=$1
54
  ERROR_MSG=$2
55
  ERROR_INFO=$3
56
  if [ ${MPID} -ne 0 ]; then 
57
    echo "`date` WARNING: $ERROR_MSG." >> $ERR_FILE
58
    if [[ ! -z  $ERROR_INFO ]]; then
59
      echo "`date` $ERROR_INFO." >> $ERR_FILE
60
    fi
61
  fi
62
}
63
64
#Timeout exists for instances where mysqld may be hung
65
TIMEOUT=10
66
67
mysql_exec() {
68
  query=$1
69
  printf "[client]\nconnect-timeout=${CLUSTER_TIMEOUT}\nuser=${CLUSTER_USERNAME}\npassword=${CLUSTER_PASSWORD}\nhost=${CLUSTER_HOSTNAME}\nport=${CLUSTER_PORT}\n" | \
70
      timeout $TIMEOUT mysql --defaults-file=/dev/stdin --protocol=tcp -Bse "${query}" 2>/dev/null
71
}
72
73
set_slave_status() {
74
  # This function checks the status of slave machines and sets their status field
75
  # The ws_ip and ws_port variables are used and must be set before calling this function
76
  if [ $debug -eq 1 ];then echo "`date` DEBUG START set_slave_status" >> $ERR_FILE;fi
77
  # This function will get and return a status of a slave node, 4=GOOD, 2=BEHIND, 0=OTHER
78
  SLAVE_STATUS=$(printf "[client]\nuser=${CLUSTER_USERNAME}\npassword=${CLUSTER_PASSWORD}\nhost=${ws_ip}\nport=${ws_port}\n" | timeout $TIMEOUT mysql --defaults-file=/dev/stdin --protocol=tcp -Bse 'SHOW SLAVE STATUS\G' 2>${PROXYSQL_DATADIR}/proxysql_admin_error_info)
79
  check_cmd $? "Cannot get status from the slave $ws_ip:$ws_port, Please check cluster login credentials" "`cat ${PROXYSQL_DATADIR}/proxysql_admin_error_info`"
80
  SLAVE_STATUS=$(echo "$SLAVE_STATUS" | sed 's/ //g')
81
  echo "$SLAVE_STATUS" | grep "^Master_Host:" >/dev/null
82
  if [ $? -ne 0 ];then
83
    # No status was found, this is not replicating
84
    if [ $debug -eq 1 ];then echo "`date` DEBUG set_slave_status: No slave status found, setting to OFFLINE_HARD, status was: $ws_status" >> $ERR_FILE;fi
85
    # Only changing the status here as another node might be in the writer hostgroup
86
    proxysql_exec "UPDATE mysql_servers set status = 'OFFLINE_HARD', weight=1000 WHERE hostname='$ws_ip' and port=$ws_port;"
87
    check_cmd $? "Cannot update Percona XtraDB Cluster node $ws_ip:$ws_port to ProxySQL database, Please check proxysql credentials" 
88
    echo "`date` ${ws_hg_id}:${i} Slave node set to OFFLINE_HARD status to ProxySQL database." >> $ERR_FILE
89
  else
90
    slave_master_host=$(echo "$SLAVE_STATUS" | grep "^Master_Host:" | cut -d: -f2)
91
    slave_io_running=$(echo "$SLAVE_STATUS" | grep "^Slave_IO_Running:" | cut -d: -f2)
92
    slave_sql_running=$(echo "$SLAVE_STATUS" | grep "^Slave_SQL_Running:" | cut -d: -f2)
93
    seconds_behind=$(echo "$SLAVE_STATUS" | grep "^Seconds_Behind_Master:" | cut -d: -f2)
94
    if [ "$seconds_behind" == "NULL" ];then
95
      # When slave_io is not working, the seconds behind value will read 'NULL', convert this to a number higher than the max
96
      let seconds_behind=SLAVE_SECONDS_BEHIND+1
97
    fi
98
    if [ "$slave_io_running" != "Yes" ] && [ "$slave_sql_running" == "Yes" ];then
99
      # Cannot connect to the master
100
      if [ "$ws_status" == "ONLINE" ];then
101
        echo "`date` Slave node (${ws_hg_id}:${i}) This slave cannot connect to it's master: $slave_master_host" >> $ERR_FILE
102
        if [ -z "$CLUSTER_OFFLINE" ];then
103
          # The cluster is up so this slave should go to OFFLINE_SOFT state
104
          proxysql_exec "UPDATE mysql_servers set hostgroup_id = $SLAVEREAD_HOSTGROUP_ID, status = 'OFFLINE_SOFT', weight=1000 WHERE hostname='$ws_ip' and port=$ws_port;"
105
          check_cmd $? "Cannot update Percona XtraDB Cluster node $ws_ip:$ws_port to ProxySQL database, Please check proxysql credentials" 
106
          echo "`date` ${ws_hg_id}:${i} Slave node set to OFFLINE_SOFT status to ProxySQL database." >> $ERR_FILE
107
        fi
108
      else
109
        if [ -n "$CLUSTER_OFFLINE" ];then
110
          # The slave is not currently online and cannot connect to its master, but we are here because all cluster nodes are down so put the slave ONLINE
111
          if [ $debug -eq 1 ];then echo "`date` DEBUG set_slave_status: Forcing slave $ws_ip:$ws_port ONLINE because cluster is offline" >> $ERR_FILE;fi
112
          proxysql_exec "UPDATE mysql_servers set status = 'ONLINE', weight=1000 WHERE hostname='$ws_ip' and port=$ws_port;"
113
          check_cmd $? "Cannot update Percona XtraDB Cluster node $ws_ip:$ws_port to ProxySQL database, Please check proxysql credentials" 
114
          echo "`date` ${SLAVEREAD_HOSTGROUP_ID}:$ws_ip:$ws_port Slave node set to ONLINE status to ProxySQL database." >> $ERR_FILE
115
        else
116
          echo "`date` Slave node (${ws_hg_id}:${i}) current status '$ws_status' in ProxySQL database!" >> $ERR_FILE
117
        fi
118
      fi
119
    elif [ "$slave_sql_running" != "Yes" ];then
120
      # Slave is not replicating
121
      if [ "$ws_status" != "OFFLINE_HARD" ];then
122
        if [ $debug -eq 1 ];then echo "`date` DEBUG set_slave_status: Setting to OFFLINE_HARD, status was: $ws_status" >> $ERR_FILE;fi
123
        proxysql_exec "UPDATE mysql_servers set hostgroup_id = $SLAVEREAD_HOSTGROUP_ID, status = 'OFFLINE_HARD', weight=1000 WHERE hostname='$ws_ip' and port=$ws_port;"
124
        check_cmd $? "Cannot update Percona XtraDB Cluster node $ws_ip:$ws_port to ProxySQL database, Please check proxysql credentials" 
125
        echo "`date` ${ws_hg_id}:${i} Slave node set to OFFLINE_HARD status to ProxySQL database." >> $ERR_FILE
126
      else
127
        echo "`date` Slave node (${ws_hg_id}:${i}) current status '$ws_status' in ProxySQL database!" >> $ERR_FILE
128
      fi
129
    elif [ $seconds_behind -gt $SLAVE_SECONDS_BEHIND ];then
130
      # Slave is more than the set number of seconds behind, return status 2
131
      if [ "$ws_status" != "OFFLINE_SOFT" ];then
132
        if [ $debug -eq 1 ];then echo "`date` DEBUG set_slave_status: Setting to OFFLINE_SOFT, status was: $ws_status" >> $ERR_FILE;fi
133
        proxysql_exec "UPDATE mysql_servers set hostgroup_id = $SLAVEREAD_HOSTGROUP_ID, status = 'OFFLINE_SOFT', weight=1000 WHERE hostname='$ws_ip' and port=$ws_port;"
134
        check_cmd $? "Cannot update Percona XtraDB Cluster node $ws_ip:$ws_port to ProxySQL database, Please check proxysql credentials" 
135
        echo "`date` ${ws_hg_id}:${i} Slave node set to OFFLINE_SOFT status to ProxySQL database." >> $ERR_FILE
136
      else
137
        echo "`date` Slave node (${ws_hg_id}:${i}) current status '$ws_status' in ProxySQL database!" >> $ERR_FILE
138
      fi
139
    else
140
      if [ "$ws_status" != "ONLINE" ];then
141
        if [ $debug -eq 1 ];then echo "`date` DEBUG set_slave_status: Setting to ONLINE, status was: $ws_status" >> $ERR_FILE;fi
142
        proxysql_exec "UPDATE mysql_servers set status = 'ONLINE', weight=1000 WHERE hostname='$ws_ip' and port=$ws_port;"
143
        check_cmd $? "Cannot update Percona XtraDB Cluster node $ws_ip:$ws_port to ProxySQL database, Please check proxysql credentials" 
144
        echo "`date` ${ws_hg_id}:${i} Slave node set to ONLINE status to ProxySQL database." >> $ERR_FILE
145
      else
146
        echo "`date` Slave node (${ws_hg_id}:${i}) current status '$ws_status' in ProxySQL database!" >> $ERR_FILE
147
      fi
148
    fi
149
  fi
150
  if [ $debug -eq 1 ];then echo "`date` DEBUG END set_slave_status" >> $ERR_FILE;fi
151
}
152
153
# Update Percona XtraDB Cluster nodes in ProxySQL database
154
update_cluster(){
155
  if [ $debug -eq 1 ];then echo "`date` DEBUG START update_cluster" >> $ERR_FILE;fi
156
  current_hosts=(`proxysql_exec "SELECT hostname,port FROM mysql_servers where hostgroup_id in ( $WRITE_HOSTGROUP_ID, $READ_HOSTGROUP_ID, $SLAVEREAD_HOSTGROUP_ID )" | sed 's|\t|:|g' | tr '\n' ' '`)
157
  wsrep_address=(`mysql_exec "SHOW STATUS LIKE 'wsrep_incoming_addresses'" | awk '{print $2}' | sed 's|,| |g'`)
158
  if [ ${#wsrep_address[@]} -eq 0 ]; then
159
    # Cluster might be down, but is there a slave to fall back to?
160
    slave_hosts=(`proxysql_exec "SELECT hostname,port FROM mysql_servers where hostgroup_id in ( $WRITE_HOSTGROUP_ID, $SLAVEREAD_HOSTGROUP_ID ) and comment = 'SLAVEREAD'" | sed 's|\t|:|g' | tr '\n' ' '`)
161
    if [ ${#slave_hosts[@]} -eq 0 ]; then
162
      echo "`date` Alert! wsrep_incoming_addresses is empty. Terminating!" >> $ERR_FILE
163
      exit 1
164
    fi
165
  fi
166
167
  for i in "${wsrep_address[@]}"; do
168
    if [[ ! " ${current_hosts[@]} " =~ " ${i} " ]]; then
169
      if [ $debug -eq 1 ];then echo "`date` DEBUG Host $i in cluster membership was not found in ProxySQL, adding it" >> $ERR_FILE;fi
170
      ws_ip=$(echo $i | cut -d':' -f1)
171
      ws_port=$(echo $i | cut -d':' -f2)
172
      ws_hg_status=$(echo `proxysql_exec "SELECT hostgroup_id,status from mysql_servers WHERE hostname='$ws_ip' and port=$ws_port"`)
173
      ws_hg_id=$(echo $ws_hg_status | cut -d' ' -f1)
174
      ws_status=$(echo $ws_hg_status | cut -d' ' -f2)
175
      echo "`date` Cluster node (${ws_hg_id}:${i}) does not exists in ProxySQL database!" >> $ERR_FILE
176
      proxysql_exec "INSERT INTO mysql_servers (hostname,hostgroup_id,port,weight,comment) VALUES ('$ws_ip',$READ_HOSTGROUP_ID,$ws_port,1000,'$MODE_COMMENT');"
177
      check_cmd $? "Cannot add Percona XtraDB Cluster node $ws_ip:$ws_port (hostgroup $READ_HOSTGROUP_ID) to ProxySQL database, Please check proxysql credentials"
178
      echo "`date` Added ${ws_hg_id}:${i} node into ProxySQL database." >> $ERR_FILE
179
      CHECK_STATUS=1
180
    fi
181
  done
182
183
  for i in "${current_hosts[@]}"; do
184
    if [[ ! " ${wsrep_address[@]} " =~ " ${i} " ]]; then
185
      if [ $debug -eq 1 ];then echo "`date` DEBUG Host $i not found in cluster membership" >> $ERR_FILE;fi
186
      # The current host in current_hosts was not found in cluster membership, set it OFFLINE_HARD unless its a slave node
187
      ws_ip=$(echo $i | cut -d':' -f1)
188
      ws_port=$(echo $i | cut -d':' -f2)
189
      ws_hg_status=$(echo `proxysql_exec "SELECT hostgroup_id,status,comment from mysql_servers WHERE hostname='$ws_ip' and port=$ws_port"`)
190
      ws_hg_id=$(echo $ws_hg_status | cut -d' ' -f1)
191
      ws_status=$(echo $ws_hg_status | cut -d' ' -f2)
192
      comment=$(echo $ws_hg_status | cut -d' ' -f3)
193
      if [ "$comment" == "SLAVEREAD" ];then
194
        if [ $debug -eq 1 ];then echo "`date` DEBUG Host $i is a slave, checking its health" >> $ERR_FILE;fi
195
        #This is a slave, check health differently
196
        set_slave_status
197
      else
198
        if [ "$ws_status" == "OFFLINE_SOFT" ]; then
199
          echo "`date` Cluster node ${ws_hg_id}:${i} does not exists in cluster membership! Changing status from OFFLINE_SOFT to OFFLINE_HARD" >> $ERR_FILE
200
          proxysql_exec "UPDATE mysql_servers set status = 'OFFLINE_HARD', hostgroup_id = $READ_HOSTGROUP_ID, comment='$MODE_COMMENT', weight=1000 WHERE hostname='$ws_ip' and port=$ws_port"
201
          check_cmd $? "Cannot update Percona XtraDB Cluster writer node in ProxySQL database, Please check proxysql credentials"
202
          CHECK_STATUS=1
203
        fi
204
        node_status=$(echo `proxysql_exec "SELECT status from mysql_servers WHERE hostname='$ws_ip' and port=$ws_port"`)
205
        echo "`date` Cluster node (${ws_hg_id}:${i}) current status '$node_status' in ProxySQL database!" >> $ERR_FILE
206
        if [ "$MODE" == "singlewrite" ]; then
207
          checkwriter_hid=`proxysql_exec "select hostgroup_id from mysql_servers where comment='WRITE' and status='ONLINE' and hostgroup_id in ($WRITE_HOSTGROUP_ID)"`
208
          if [[ -z "$checkwriter_hid" ]]; then
209
            current_hosts=(`proxysql_exec "SELECT hostname,port FROM mysql_servers WHERE  status='ONLINE' and comment='READ' and hostgroup_id='$READ_HOSTGROUP_ID' ORDER BY random() LIMIT 1" | sed 's|\t|:|g' | tr '\n' ' '`)
210
            ws_ip=$(echo $current_hosts | cut -d':' -f1)
211
            ws_port=$(echo $current_hosts | cut -d':' -f2)
212
            echo "`date` No writer found, promoting $ws_ip:$ws_port as writer node!" >> $ERR_FILE
213
            proxysql_exec "UPDATE mysql_servers set hostgroup_id = $WRITE_HOSTGROUP_ID, comment='WRITE', weight=1000000 WHERE hostname='$ws_ip' and port=$ws_port"
214
            check_cmd $? "Cannot update Percona XtraDB Cluster writer node in ProxySQL database, Please check proxysql credentials"
215
            CHECK_STATUS=1
216
          fi
217
        fi
218
        
219
      fi
220
    fi
221
  done
222
223
  for i in "${wsrep_address[@]}"; do
224
    if [[ ! " ${current_hosts[@]} " == " ${i} " ]]; then
225
      if [ $debug -eq 1 ];then echo "`date` DEBUG Host $i was found in cluster membership" >> $ERR_FILE;fi
226
      # current_hosts contains the node in wsrep_addresses
227
      ws_ip=$(echo $i | cut -d':' -f1)
228
      ws_port=$(echo $i | cut -d':' -f2)
229
      ws_hg_status=$(echo `proxysql_exec "SELECT hostgroup_id,status from mysql_servers WHERE hostname='$ws_ip' and port=$ws_port"`)
230
      ws_hg_id=$(echo $ws_hg_status | cut -d' ' -f1)
231
      ws_status=$(echo $ws_hg_status | cut -d' ' -f2)
232
      echo "`date` Cluster node (${ws_hg_id}:${i}) current status '$ws_status' in ProxySQL database!" >> $ERR_FILE 
233
      if [ "$ws_status" == "OFFLINE_HARD" ]; then
234
        # The node was OFFLINE_HARD, but its now in the cluster list so lets make it OFFLINE_SOFT
235
        proxysql_exec "UPDATE mysql_servers set status = 'OFFLINE_SOFT', weight=1000 WHERE hostname='$ws_ip' and port=$ws_port;"
236
        check_cmd $? "Cannot update Percona XtraDB Cluster node $ws_ip:$ws_port to ProxySQL database, Please check proxysql credentials" 
237
        echo "`date` ${ws_hg_id}:${i} node set to OFFLINE_SOFT status to ProxySQL database." >> $ERR_FILE
238
        CHECK_STATUS=1
239
      fi
240
    fi
241
  done
242
  if [ $debug -eq 1 ];then echo "`date` DEBUG End update_cluster" >> $ERR_FILE;fi
243
}
244
245
mode_change_check(){
246
  if [ $debug -eq 1 ];then echo "`date` DEBUG START mode_change_check" >> $ERR_FILE;fi
247
248
  if [ -f $HOST_PRIORITY_FILE ];then
249
    # Get the list of hosts from the host_priority file ignoring blanks and any lines that start with '#'
250
    priority_hosts=(`cat $HOST_PRIORITY_FILE | grep ^[^#]`)
251
  fi
252
  #   File sample:
253
  #   10.11.12.21:3306
254
  #   10.21.12.21:3306
255
  #   10.31.12.21:3306
256
  #
257
258
  # Check if the current writer is in an OFFLINE_SOFT state
259
  checkwriter_hid=`proxysql_exec "select hostgroup_id from mysql_servers where comment in ('WRITE', 'READWRITE') and status='OFFLINE_SOFT' and hostgroup_id in ($WRITE_HOSTGROUP_ID)"`
260
  if [[ -n "$checkwriter_hid" ]]; then
261
    # Found a writer node that was in 'OFFLINE_SOFT' state, move it to the READ hostgroup unless the MODE is 'loadbal'
262
    if [ "$MODE" != "loadbal" ];then
263
      if [ $debug -eq 1 ];then echo "`date` DEBUG mode_change_check: Found OFFLINE_SOFT writer, changing to READ status and hostgroup $READ_HOSTGROUP_ID" >> $ERR_FILE;fi
264
      proxysql_exec "UPDATE mysql_servers set hostgroup_id = $READ_HOSTGROUP_ID, comment='READ', weight=1000 WHERE comment='WRITE' and status='OFFLINE_SOFT' and hostgroup_id='$WRITE_HOSTGROUP_ID'"
265
      check_cmd $? "Cannot update Percona XtraDB Cluster writer node in ProxySQL database, Please check proxysql credentials"
266
      CHECK_STATUS=1
267
    fi
268
269
    # If that temp file exists use it otherwise choose random as is done now
270
    unset current_hosts
271
    if [ -z $priority_hosts ];then
272
      # Order file wasn't found, behave as before
273
      current_hosts=(`proxysql_exec "SELECT hostname,port FROM mysql_servers WHERE status='ONLINE' and comment in ('READ', 'READWRITE') and hostgroup_id='$READ_HOSTGROUP_ID' ORDER BY random() LIMIT 1" | sed 's|\t|:|g' | tr '\n' ' '`)
274
    else
275
      # Get the list of all ONLINE reader nodes in ProxySQL
276
      current_hosts=(`proxysql_exec "SELECT hostname,port FROM mysql_servers WHERE status='ONLINE' and comment='READ' and hostgroup_id='$READ_HOSTGROUP_ID' " | sed 's|\t|:|g' | tr '\n' ' '`)
277
278
      # Find the highest priority host from the online reader hosts
279
      for i in "${priority_hosts[@]}"; do
280
        if [[ " ${current_hosts[@]} " =~ " ${i} " ]]; then
281
          # This host in priority_hosts was found in the list of current_hosts
282
          current_hosts=${i}
283
          found_host=1
284
          break
285
        fi
286
      done
287
      if [ -z $found_host ];then
288
        # None of the priority hosts were found as active, picking the first on the list from what is available.
289
        current_hosts=(`echo $current_hosts | cut -d' ' -f1`)
290
        unset found_host
291
      fi
292
    fi
293
294
    # If the $current_hosts variabe is empty here then it's time to put the SLAVEREAD node in if there is one
295
    if [ -z "$current_hosts" ];then
296
      # Verify a slave is not already in the write hostgroup
297
      if [ $debug -eq 1 ];then echo "`date` DEBUG mode_change_check: No cluster members available, check if any slaves are already in the writer hostgroup" >> $ERR_FILE;fi
298
      slave_check=(`proxysql_exec "SELECT hostname,port FROM mysql_servers WHERE status='ONLINE' and comment='SLAVEREAD' and hostgroup_id=$WRITE_HOSTGROUP_ID ORDER BY random() LIMIT 1" | sed 's|\t|:|g' | tr '\n' ' '`)
299
      if [ -z "$slave_check" ];then
300
        # no slaves were currently in the writer group
301
        if [ $debug -eq 1 ];then echo "`date` DEBUG mode_change_check: No slaves currently in the writer group" >> $ERR_FILE;fi
302
        current_hosts=(`proxysql_exec "SELECT hostname,port FROM mysql_servers WHERE status='ONLINE' and comment='SLAVEREAD' ORDER BY random() LIMIT 1" | sed 's|\t|:|g' | tr '\n' ' '`)
303
        slave_write="1"
304
      else
305
        if [ $debug -eq 1 ];then echo "`date` DEBUG mode_change_check: A slave is already in the writer hostgroup" >> $ERR_FILE;fi
306
      fi
307
    fi
308
309
    ws_ip=$(echo $current_hosts | cut -d':' -f1)
310
    ws_port=$(echo $current_hosts | cut -d':' -f2)
311
312
    # If the cluster is failed and a slave was already in as writer, the current_hosts variable will be empty
313
    if [ "$slave_write" == "1" ] && [ -n "$current_hosts" ];then
314
      if [ $debug -eq 1 ];then echo "`date` DEBUG mode_change_check1: Changing $ws_ip:$ws_port to hostgroup $WRITE_HOSTGROUP_ID" >> $ERR_FILE;fi
315
      proxysql_exec "UPDATE mysql_servers set hostgroup_id = $WRITE_HOSTGROUP_ID, weight=$WRITE_WEIGHT WHERE hostname='$ws_ip' and port=$ws_port"
316
      check_cmd $? "Cannot update Percona XtraDB Cluster writer node in ProxySQL database, Please check proxysql credentials"
317
      echo "`date` $ws_ip:$ws_port (slave) is ONLINE, switching to write hostgroup" >> $ERR_FILE
318
      CHECK_STATUS=1
319
    elif [ "$MODE" != "loadbal" ] && [ -n "$current_hosts" ];then
320
      # Only do this if the MODE is not 'loadbal'
321
      if [ $debug -eq 1 ];then echo "`date` DEBUG mode_change_check1: Changing $ws_ip:$ws_port to WRITE status and hostgroup $WRITE_HOSTGROUP_ID" >> $ERR_FILE;fi
322
      proxysql_exec "UPDATE mysql_servers set hostgroup_id = $WRITE_HOSTGROUP_ID, comment='WRITE', weight=$WRITE_WEIGHT WHERE hostname='$ws_ip' and port=$ws_port"
323
      check_cmd $? "Cannot update Percona XtraDB Cluster writer node in ProxySQL database, Please check proxysql credentials"
324
      echo "`date` $ws_ip:$ws_port is ONLINE, switching to write hostgroup" >> $ERR_FILE
325
      CHECK_STATUS=1
326
    fi
327
  else
328
    # The current writer was not in OFFLINE_SOFT state
329
    # Now check if the current writer is a slave node and pull it out if other nodes are available
330
    # Should check if a slave is the current writer and pull it out if a cluster node is available
331
    checkslave_hid=`proxysql_exec "select hostgroup_id from mysql_servers where hostgroup_id='$WRITE_HOSTGROUP_ID' AND comment='SLAVEREAD'"`
332
    # Set a variable containing a random available cluster node
333
    available_cluster_hosts=(`proxysql_exec "SELECT hostname,port FROM mysql_servers WHERE status='ONLINE' and comment in ('READ', 'READWRITE') ORDER BY random() LIMIT 1" | sed 's|\t|:|g' | tr '\n' ' '`)
334
    if [[ -n "$checkslave_hid" ]]; then
335
      # The current writer is a slave, check for other ONLINE nodes to put in
336
      if [ -n "$available_cluster_hosts" ];then
337
        # There is a regular cluster node available, pull out the slave
338
        if [ $debug -eq 1 ];then echo "`date` DEBUG mode_change_check1: Changing any SLAVEREAD nodes in hostgroup $WRITE_HOSTGROUP_ID to hostgroup $SLAVEREAD_HOSTGROUP_ID" >> $ERR_FILE;fi
339
        proxysql_exec "UPDATE mysql_servers set hostgroup_id = $SLAVEREAD_HOSTGROUP_ID, weight=1000 WHERE hostgroup_id='$WRITE_HOSTGROUP_ID' and comment='SLAVEREAD'"
340
        check_cmd $? "Cannot update Percona XtraDB Cluster writer node in ProxySQL database, Please check proxysql credentials"
341
        writer_was_slave=1
342
      fi
343
    fi
344
345
    if [ -z $priority_hosts ];then
346
      # Order file wasn't found
347
      # Do not change the config of a cluster node if the MODE is 'loadbal'
348
      if [ -n "$available_cluster_hosts" ] && [ -n "$writer_was_slave" ] && [ "$MODE" != "loadbal" ];then
349
        # There is a regular cluster node available, put it back in the writer hostgroup
350
        ws_ip=$(echo $available_cluster_hosts | cut -d':' -f1)
351
        ws_port=$(echo $available_cluster_hosts | cut -d':' -f2)
352
        if [ $debug -eq 1 ];then echo "`date` DEBUG mode_change_check2: Changing $ws_ip:$ws_port to WRITE status and hostgroup $WRITE_HOSTGROUP_ID" >> $ERR_FILE;fi
353
        proxysql_exec "UPDATE mysql_servers set hostgroup_id = $WRITE_HOSTGROUP_ID, comment='WRITE', weight=$WRITE_WEIGHT WHERE hostname='$ws_ip' and port=$ws_port"
354
        check_cmd $? "Cannot update Percona XtraDB Cluster writer node in ProxySQL database, Please check proxysql credentials"
355
        echo "`date` $ws_ip:$ws_port is ONLINE, switching to write hostgroup" >> $ERR_FILE
356
        CHECK_STATUS=1
357
      fi
358
    else
359
      # Check here if the highest priority node is the writer
360
      # Get the list of all ONLINE nodes in ProxySQL, can't use available_cluster_hosts here
361
      current_hosts=(`proxysql_exec "SELECT hostname,port FROM mysql_servers WHERE status='ONLINE' and hostgroup_id in($READ_HOSTGROUP_ID,$WRITE_HOSTGROUP_ID) AND comment<>'SLAVEREAD'" | sed 's|\t|:|g' | tr '\n' ' '`)
362
363
      # Find the highest priority host from the online hosts
364
      for i in "${priority_hosts[@]}"; do
365
        if [[ " ${current_hosts[@]} " =~ " ${i} " ]]; then
366
          # This host in priority_hosts was found in the list of current_hosts
367
          current_hosts=${i}
368
          found_host=1
369
          break
370
        fi
371
      done
372
373
      # Only initiate changing hosts if a more priority host was found
374
      if [ -n $found_host ];then
375
        # Check to see if the host in 'current_host' is the writer
376
        current_writer=(`proxysql_exec "SELECT hostname,port FROM mysql_servers WHERE status='ONLINE' and comment='WRITE' and hostgroup_id=$WRITE_HOSTGROUP_ID" | sed 's|\t|:|g' | tr '\n' ' '`)
377
        if [ "$current_hosts" != "$current_writer" ];then
378
          # Switch the writer around
379
          if [ -n "$current_writer" ];then
380
            # Move the current writer host to reader hostgroup if there is one
381
            ws_ip=$(echo $current_writer | cut -d':' -f1)
382
            ws_port=$(echo $current_writer | cut -d':' -f2)
383
            if [ $debug -eq 1 ];then echo "`date` DEBUG mode_change_check3: Changing $ws_ip:$ws_port to READ status and hostgroup $READ_HOSTGROUP_ID" >> $ERR_FILE;fi
384
            proxysql_exec "UPDATE mysql_servers set hostgroup_id = $READ_HOSTGROUP_ID, comment='READ', weight=1000 WHERE hostname='$ws_ip' and port=$ws_port"
385
            check_cmd $? "Cannot update Percona XtraDB Cluster reader node in ProxySQL database, Please check proxysql credentials"
386
            echo "`date` $ws_ip:$ws_port is ONLINE but a higher priority node is available, switching to read hostgroup" >> $ERR_FILE
387
          fi
388
          # Move the priority host to the writer hostgroup
389
          ws_ip=$(echo $current_hosts | cut -d':' -f1)
390
          ws_port=$(echo $current_hosts | cut -d':' -f2)
391
          if [ $debug -eq 1 ];then echo "`date` DEBUG mode_change_check3: Changing $ws_ip:$ws_port to WRITE status and hostgroup $WRITE_HOSTGROUP_ID" >> $ERR_FILE;fi
392
          proxysql_exec "UPDATE mysql_servers set hostgroup_id = $WRITE_HOSTGROUP_ID, comment='WRITE', weight=$WRITE_WEIGHT WHERE hostname='$ws_ip' and port=$ws_port"
393
          check_cmd $? "Cannot update Percona XtraDB Cluster writer node in ProxySQL database, Please check proxysql credentials"
394
          echo "`date` $ws_ip:$ws_port is ONLINE and highest priority, switching to write hostgroup" >> $ERR_FILE
395
          CHECK_STATUS=1
396
        fi
397
      else
398
        if [ -n "$available_cluster_hosts" ] && [ -n "$writer_was_slave" ];then
399
          # There is a regular cluster node available, pull out the slave and put the cluster node back in the writer hostgroup
400
          ws_ip=$(echo $available_cluster_hosts | cut -d':' -f1)
401
          ws_port=$(echo $available_cluster_hosts | cut -d':' -f2)
402
          if [ $debug -eq 1 ];then echo "`date` DEBUG mode_change_check4: Changing $ws_ip:$ws_port to hostgroup $WRITE_HOSTGROUP_ID" >> $ERR_FILE;fi
403
          proxysql_exec "UPDATE mysql_servers set hostgroup_id = $WRITE_HOSTGROUP_ID, weight=$WRITE_WEIGHT WHERE hostname='$ws_ip' and port=$ws_port"
404
          check_cmd $? "Cannot update Percona XtraDB Cluster writer node in ProxySQL database, Please check proxysql credentials"
405
          echo "`date` $ws_ip:$ws_port is ONLINE, switching to write hostgroup" >> $ERR_FILE
406
          CHECK_STATUS=1
407
        fi
408
      fi
409
    fi
410
  fi
411
  if [ $debug -eq 1 ];then echo "`date` DEBUG END mode_change_check" >> $ERR_FILE;fi
412
}
413
414
# Monitoring user needs 'REPLICATION CLIENT' privilege
415
echo "`date` ###### Percona XtraDB Cluster status ######" >> $ERR_FILE
416
CLUSTER_USERNAME=$(proxysql_exec "SELECT variable_value FROM global_variables WHERE variable_name='mysql-monitor_username'")
417
check_cmd $? "Could not retrieve cluster login info from ProxySQL. Please check cluster login credentials"
418
419
CLUSTER_PASSWORD=$(proxysql_exec "SELECT variable_value FROM global_variables WHERE variable_name='mysql-monitor_password'") 
420
check_cmd $? "Could not retrieve cluster login info from ProxySQL. Please check cluster login credentials"
421
422
CLUSTER_HOST_INFO=`proxysql_exec "SELECT hostname,port FROM mysql_servers WHERE status='ONLINE' and comment<>'SLAVEREAD' and hostgroup_id in ($WRITE_HOSTGROUP_ID, $READ_HOSTGROUP_ID) limit 1"`
423
check_cmd $? "Could not retrieve cluster node info from ProxySQL. Please check cluster login credentials"
424
425
CLUSTER_HOSTS=($(proxysql_exec "SELECT hostname || '-' || port FROM mysql_servers WHERE status='ONLINE' and comment<>'SLAVEREAD' and hostgroup_id in ($WRITE_HOSTGROUP_ID, $READ_HOSTGROUP_ID)"))
426
CLUSTER_TIMEOUT=($(proxysql_exec "SELECT MAX(interval_ms / 1000 - 1, 1) FROM scheduler"))
427
428
for i in "${CLUSTER_HOSTS[@]}"; do
429
  CLUSTER_HOSTNAME=$(echo $i | cut -d'-' -f1)
430
  CLUSTER_PORT=$(echo $i | cut -d'-' -f2)
431
  CHECK_SERVER_STATUS=$(mysql_exec "SELECT @@port")
432
  if [[ -n $CHECK_SERVER_STATUS ]]; then
433
    CLUSTER_HOST_INFO="${CHECK_SERVER_STATUS}"
434
    break
435
  else
436
    CLUSTER_HOST_INFO=""
437
  fi  
438
done
439
440
if [[ -z $CLUSTER_HOST_INFO ]]; then
441
  if [ $debug -eq 1 ];then echo "`date` DEBUG Can't get cluster info, checking if a slave is available" >> $ERR_FILE;fi
442
  # Set CLUSTER_OFFLINE variable, used my the set_slave_status function and the bottom of this script
443
  CLUSTER_OFFLINE=1
444
  # No Cluster nodes are available, but is a slave available?
445
  SLAVE_CHECK=`proxysql_exec "SELECT hostname,port FROM mysql_servers WHERE comment='SLAVEREAD' limit 1"`
446
  if [[ ! -z $SLAVE_CHECK ]]; then
447
    SLAVE_HOST_INFO=`proxysql_exec "SELECT hostname,port FROM mysql_servers WHERE status='ONLINE' and comment='SLAVEREAD' and hostgroup_id in ($WRITE_HOSTGROUP_ID, $SLAVEREAD_HOSTGROUP_ID) limit 1"`
448
    check_cmd $? "Could not retrieve cluster login info from ProxySQL. Please check cluster login credentials"
449
    if [[ -z $SLAVE_HOST_INFO ]]; then
450
      if [ $debug -eq 1 ];then echo "`date` DEBUG No online slaves were found, will recheck" >> $ERR_FILE;fi
451
      # Check for a slave in a status other than 'ONLINE'
452
      # This is an emergency measure, just put a random slave online
453
      # Would be nice to try to find the most up to date slave if there is more than one, but that would require
454
      # a query to all slaves to check their positions, probably not worth the overhead - something to think about
455
      slave_host=(`proxysql_exec "SELECT hostname,port FROM mysql_servers where comment='SLAVEREAD' and hostgroup_id in ($WRITE_HOSTGROUP_ID, $SLAVEREAD_HOSTGROUP_ID) ORDER BY random() LIMIT 1" | sed 's|\t|:|g' | tr '\n' ' '`)
456
      if [ $debug -eq 1 ];then echo "`date` DEBUG Trying to bring slave: $slave_host ONLINE due to cluster being down" >> $ERR_FILE;fi
457
      ws_ip=$(echo $slave_host | cut -d':' -f1)
458
      ws_port=$(echo $slave_host | cut -d':' -f2)
459
      set_slave_status
460
    else
461
      if [ $debug -eq 1 ];then echo "`date` DEBUG online slaves were found" >> $ERR_FILE;fi
462
      # Run function here to move the slave into the write hostgroup
463
      mode_change_check
464
    fi
465
  fi
466
  SLAVE_HOST_INFO=`proxysql_exec "SELECT hostname,port FROM mysql_servers WHERE status='ONLINE' and comment='SLAVEREAD' and hostgroup_id='$WRITE_HOSTGROUP_ID' limit 1"`
467
  if [[ -z $SLAVE_HOST_INFO ]]; then
468
    offline_hosts=(`proxysql_exec "SELECT hostgroup_id,hostname,port,status FROM mysql_servers where hostgroup_id in ( $WRITE_HOSTGROUP_ID, $READ_HOSTGROUP_ID, $SLAVEREAD_HOSTGROUP_ID )" | sed 's|\t|:|g' | tr '\n' ' '`)
469
    for i in "${offline_hosts[@]}"; do
470
      offline_host=(`echo ${i} | awk -F: '{print $1 ":" $2 ":" $3}'`)
471
      offline_host_status=(`echo ${i} | cut -d':' -f4`)
472
      echo "`date` Cluster node ($offline_host) current status '$offline_host_status' in ProxySQL database!" >> $ERR_FILE
473
    done
474
  else
475
    echo "`date` Percona XtraDB Cluster nodes are offline, a slave node is in the writer hostgroup, please check status" >> $ERR_FILE
476
  fi
477
else
478
  update_cluster
479
  mode_change_check
480
fi
481
482
if [ $CHECK_STATUS -eq 0 ]; then
483
  if [ -z "$CLUSTER_OFFLINE" ];then
484
    echo "`date` Percona XtraDB Cluster membership looks good" >> $ERR_FILE
485
  else
486
    echo "`date` Percona XtraDB Cluster is offline!" >> $ERR_FILE
487
  fi
488
else
489
  echo "`date` ###### Loading mysql_servers config into runtime ######" >> $ERR_FILE
490
  proxysql_exec "LOAD MYSQL SERVERS TO RUNTIME"
491
fi
492
exit 0
493