forked from Flowman/docker-pxc-clustercheck
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathclustercheck
133 lines (115 loc) · 6.01 KB
/
clustercheck
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env python
import sys
from twisted.web import server, resource
from twisted.internet import reactor
import MySQLdb
import MySQLdb.cursors
import optparse
import time
'''
__author__="See AUTHORS.txt at https://github.com/Oneiroi/clustercheck"
__copyright__="David Busby, Percona Ireland Ltd"
__license__="GNU v3 + section 7: Redistribution/Reuse of this code is permitted under the GNU v3 license, as an additional term ALL code must carry the original Author(s) credit in comment form."
__dependencies__="MySQLdb (python26-mysqldb (el5) / MySQL-python (el6) / python-mysqldb (ubuntu) / python-twisted >= 12.2)"
__description__="Provides a stand alone http service, evaluating wsrep_local_state intended for use with HAProxy. Listens on 8000"
'''
class opts:
available_when_donor = 0
disable_when_ro = 0
is_ro = 0
cache_time = 1
last_query_time = 0
last_query_result = 0
cnf_file = '~/.my.cnf'
being_updated = False
# Overriding the connect timeout so that status check doesn't hang
c_timeout = 10
class ServerStatus(resource.Resource):
isLeaf = True
def render_OPTIONS(self, request):
return self.render_GET(request)
def render_GET(self, request):
conn = None
res = ''
httpres = ''
ctime = time.time()
ttl = opts.last_query_time + opts.cache_time - ctime
request.setHeader("Server", "PXC Python clustercheck / 2.0")
if (ttl <= 0) and opts.being_updated == False:
#cache expired
opts.being_updated = True #prevent mutliple threads falling through to MySQL for update
opts.last_query_time = ctime
#add some informational headers
request.setHeader("X-Cache", [False, ])
try:
#conn = MySQLdb.connect(read_default_file = opts.cnf_file,
conn = MySQLdb.connect(host = "localhost",
user = "clustercheckuser",
passwd = "clustercheckpassword!",
connect_timeout = opts.c_timeout,
cursorclass = MySQLdb.cursors.DictCursor)
if conn:
curs = conn.cursor()
curs.execute("SHOW STATUS LIKE 'wsrep_local_state'")
res = curs.fetchall()
opts.last_query_response = res
if opts.disable_when_ro:
curs.execute("SHOW VARIABLES LIKE 'read_only'")
ro = curs.fetchone()
if ro['Value'].lower() in ('on', '1'):
res = () #read_only is set and opts.disable_when_ro is also set, we should return this node as down
opts.is_ro = True
conn.close() #we're done with the connection let's not hang around
opts.being_updated = False #reset the flag
except MySQLdb.Error, e:
sys.stderr.write("[ERROR] %d: %s\n" % (e.args[0], e.args[1]))
opts.being_updated = False
except MySQLdb.OperationalError:
opts.being_updated = False #corrects bug where the flag is never reset on a communication failiure
else:
#add some informational headers
request.setHeader("X-Cache", True)
request.setHeader("X-Cache-TTL", "%d" % ttl)
request.setHeader("X-Cache-Updating", opts.being_updated)
request.setHeader("X-Cache-disable-when-RO", opts.disable_when_ro)
request.setHeader("X-Cache-node-is-RO", opts.is_ro)
#run from cached response
res = opts.last_query_response
if len(res) == 0:
request.setResponseCode(503)
request.setHeader("Content-type", "text/html")
httpres = "Percona XtraDB Cluster Node state could not be retrieved."
res=()
opts.last_query_response = res
elif res[0]['Value'] == '4' or (int(opts.available_when_donor) == 1 and res[0]['Value'] == '2'):
request.setResponseCode(200)
request.setHeader("Content-type", "text/html")
httpres = "Percona XtraDB Cluster Node is synced."
else:
request.setResponseCode(503)
request.setHeader("Content-type", "text/html")
httpres = "Percona XtraDB Cluster Node is not synced."
return httpres
"""
Usage:
pyclustercheck &>$LOGFILE &
To test:
curl http://127.0.0.1:8000
"""
if __name__ == '__main__':
parser = optparse.OptionParser()
parser.add_option('-a','--available-when-donor', dest='awd', default=0, help="Available when donor [default: %default]")
parser.add_option('-r','--disable-when-readonly', action='store_true', dest='dwr', default=False, help="Disable when read_only flag is set (desirable when wanting to take a node out of the cluster wihtout desync) [default: %default]")
parser.add_option('-c','--cache-time', dest='cache', default=1, help="Cache the last response for N seconds [default: %default]")
parser.add_option('-f','--conf', dest='cnf', default='~/.my.cnf', help="MySQL Config file to use [default: %default]")
parser.add_option('-p','--port', dest='port', default=8000, help="Port to listen on [default: %default]")
parser.add_option('-6','--ipv6', dest='ipv6', action='store_true', default=False, help="Listen to ipv6 only (disabled ipv4) [default: %default]")
parser.add_option('-4','--ipv4', dest='ipv4', default='0.0.0.0', help="Listen to ipv4 on this address [default: %default]")
options, args = parser.parse_args()
opts.available_when_donor = options.awd
opts.disable_when_ro = options.dwr
opts.cnf_file = options.cnf
opts.cache_time = int(options.cache)
bind = "::" if options.ipv6 else options.ipv4
reactor.listenTCP(int(options.port), server.Site(ServerStatus()), interface=bind)
reactor.run()