From 0e39671094edcc07797b9f4b93bdfa90f0283adf Mon Sep 17 00:00:00 2001 From: Vladislav Nazarenko Date: Wed, 16 Apr 2014 14:45:59 +0200 Subject: [PATCH 01/13] fix: the script was not working with apache 2.2.15 (redhat 6.5) --- balancer-manage.py | 47 +++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) mode change 100755 => 100644 balancer-manage.py diff --git a/balancer-manage.py b/balancer-manage.py old mode 100755 new mode 100644 index 6f9c4ed..5ab7c55 --- a/balancer-manage.py +++ b/balancer-manage.py @@ -1,13 +1,14 @@ #!/usr/bin/python -O - +# # Author: Florian Lambert - -# Allow you to manage Worker/BalancerMember defined in your apache2 mod_proxy conf : +# Source: https://github.com/talset/apache-tools +# +# Allow you to manage Worker/BalancerMember defined in your apache2 mod_proxy conf : # # BalancerMember ajp://10.152.45.1:8001 route=web1 retry=60 # BalancerMember ajp://10.152.45.2:8001 route=web2 retry=60 # - +# # You have to allow /balancer-manager #Like : # ProxyPass /balancer-manager ! @@ -17,15 +18,14 @@ # Deny from all # Allow from 127.0.0.1 # - +# # Verify url="http....." - # -#HOW TO : # -#./balancer-manager.py -l -#./balancer-manager.py -w ajp://10.152.45.1:8001 -a enable - +# HOW TO : +# balancer-manager.py -l +# balancer-manager.py -w ajp://10.152.45.1:8001 -a enable +# import argparse import re import HTMLParser @@ -34,9 +34,9 @@ # Get args PARSER = argparse.ArgumentParser() -PARSER.add_argument("-l", "--list", +PARSER.add_argument("-l", "--list", help="List Worker member and status", action='store_true') -PARSER.add_argument("-a", "--action", +PARSER.add_argument("-a", "--action", help="\"enable\" or \"disable\" the specified Worker", type=str) PARSER.add_argument("-w", "--worker", help="Worker name : example ajp://127.0.0.1:8001", type=str) @@ -59,48 +59,49 @@ def __init__(self): self._tds=[] HTMLParser.HTMLParser.__init__(self) self.in_td = False - + def handle_starttag(self, tag, attrs): if tag == 'td' or tag == 'th': self.in_td = True - + def handle_data(self, data): if self.in_td: self._tds.append(data) - + def handle_endtag(self, tag): self.in_td = False if tag == 'tr': self.datas.append(self._tds) self._tds = [] - + p = TableParser() p.feed(f.read()) - template = " {Worker:40} | {Status:10} | {Elected:10}" - - print template.format(Worker="Worker",Status="Status",Elected="Elected") + template = " {Worker:40} | {Status:10} | {Elected:10} | {To:10} | {From:10}" + + print template.format(Worker="Worker",Status="Status",Elected="Elected", To="To", From="From") for v in p.datas[2:]: - print template.format(Worker=v[0],Status=v[4],Elected=v[5]) + print template.format(Worker=v[0],Status=v[3].split(" ")[1],Elected=v[4], To=v[5], From=v[6]) def balancer_manage(action, worker): #Read informations req = Request(url, None, headers) f = urlopen(req) - + #Find balancer and nonce result = re.search("b=([^&]+)&w="+worker+"&nonce=([^\"]+)", f.read()) if result is not None: balancer = result.group(1) nonce = result.group(2) #Generate URL - params = urlencode({'b': balancer, 'w': worker, 'dw': action, 'nonce': nonce}) + action = (0,1)[action == 'disable'] + params = urlencode({'b': balancer, 'w': worker, 'status_D': action, 'nonce': nonce}) req = Request(url+"?%s" % params, None, headers) f = urlopen(req) print "Action\n Worker %s [%s]\n\nStatus" % (worker,action) balancer_status() - + if __name__ == "__main__": From d1c0d7d32a064e13220ab3c2e23c10d727f1834c Mon Sep 17 00:00:00 2001 From: Vladislav Nazarenko Date: Wed, 16 Apr 2014 16:09:53 +0200 Subject: [PATCH 02/13] upd: added host and port args --- balancer-manage.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) mode change 100644 => 100755 balancer-manage.py diff --git a/balancer-manage.py b/balancer-manage.py old mode 100644 new mode 100755 index 5ab7c55..50a31a9 --- a/balancer-manage.py +++ b/balancer-manage.py @@ -34,6 +34,8 @@ # Get args PARSER = argparse.ArgumentParser() +PARSER.add_argument("-H", "--host", help="Host connect to", type=str) +PARSER.add_argument("-p", "--port", help="Port connect to", type=str) PARSER.add_argument("-l", "--list", help="List Worker member and status", action='store_true') PARSER.add_argument("-a", "--action", @@ -42,11 +44,23 @@ help="Worker name : example ajp://127.0.0.1:8001", type=str) ARGS = PARSER.parse_args() -#Fix if necessary -#vhostname -headers = {"Host": '127.0.0.1' } -#ip to reach apache -url="http://127.0.0.1/balancer-manager" +############################################################################# +# default values + +host='localhost' +port = 80 + +if ARGS.host: + host = ARGS.host + if ARGS.port: port = ARGS.port + +if ARGS.port: + port = ARGS.port + +url="http://%s:%s/balancer-manager" % (host, port) + +############################################################################# +# functions def balancer_status(): req = Request(url, None, headers) From 3c437d463e4037ef6328fbc1562bc1d914f1dc0b Mon Sep 17 00:00:00 2001 From: Vladislav Nazarenko Date: Wed, 16 Apr 2014 16:11:37 +0200 Subject: [PATCH 03/13] upd: exit status, urlparse --- balancer-manage.py | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/balancer-manage.py b/balancer-manage.py index 50a31a9..37bae30 100755 --- a/balancer-manage.py +++ b/balancer-manage.py @@ -29,9 +29,14 @@ import argparse import re import HTMLParser -from urllib import urlencode -from urllib2 import Request, urlopen +import sys +from urllib import urlencode +from urllib2 import Request +from urllib2 import urlopen +from urlparse import urlparse + +############################################################################# # Get args PARSER = argparse.ArgumentParser() PARSER.add_argument("-H", "--host", help="Host connect to", type=str) @@ -94,11 +99,20 @@ def handle_endtag(self, tag): template = " {Worker:40} | {Status:10} | {Elected:10} | {To:10} | {From:10}" print template.format(Worker="Worker",Status="Status",Elected="Elected", To="To", From="From") - for v in p.datas[2:]: - print template.format(Worker=v[0],Status=v[3].split(" ")[1],Elected=v[4], To=v[5], From=v[6]) + for v in p.datas: + r = urlparse(v[0]) + if r.scheme: + # the URL is parsable + print template.format(Worker=v[0],Status=v[3],Elected=v[4], To=v[5], From=v[6]) + template.format(Worker=v[0],Status=v[3],Elected=v[4], To=v[5], From=v[6]) + + +def balancer_manage(sAction, worker): + if sAction not in ['enable', 'disable']: + print "Unknown action: %s" %(sAction) + return 1 -def balancer_manage(action, worker): #Read informations req = Request(url, None, headers) f = urlopen(req) @@ -109,11 +123,11 @@ def balancer_manage(action, worker): balancer = result.group(1) nonce = result.group(2) #Generate URL - action = (0,1)[action == 'disable'] + action = (0,1)[sAction == 'disable'] params = urlencode({'b': balancer, 'w': worker, 'status_D': action, 'nonce': nonce}) req = Request(url+"?%s" % params, None, headers) f = urlopen(req) - print "Action\n Worker %s [%s]\n\nStatus" % (worker,action) + print "Action\n Worker %s [%s]\n\nStatus" % (worker,sAction) balancer_status() @@ -123,5 +137,6 @@ def balancer_manage(action, worker): if ARGS.list : balancer_status() elif ARGS.action and ARGS.worker: - balancer_manage(ARGS.action,ARGS.worker) + r = balancer_manage(ARGS.action,ARGS.worker) + sys.exit(r) else : PARSER.print_help() From c5d5c1cccfca310f0d8c38bf92a4beb3eac1bef9 Mon Sep 17 00:00:00 2001 From: Vladislav Nazarenko Date: Wed, 16 Apr 2014 16:16:52 +0200 Subject: [PATCH 04/13] upd: removed headers --- balancer-manage.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/balancer-manage.py b/balancer-manage.py index 37bae30..27c3212 100755 --- a/balancer-manage.py +++ b/balancer-manage.py @@ -68,7 +68,7 @@ # functions def balancer_status(): - req = Request(url, None, headers) + req = Request(url, None) f = urlopen(req) #print f.read() @@ -114,7 +114,7 @@ def balancer_manage(sAction, worker): return 1 #Read informations - req = Request(url, None, headers) + req = Request(url, None) f = urlopen(req) #Find balancer and nonce @@ -125,7 +125,7 @@ def balancer_manage(sAction, worker): #Generate URL action = (0,1)[sAction == 'disable'] params = urlencode({'b': balancer, 'w': worker, 'status_D': action, 'nonce': nonce}) - req = Request(url+"?%s" % params, None, headers) + req = Request(url+"?%s" % params, None) f = urlopen(req) print "Action\n Worker %s [%s]\n\nStatus" % (worker,sAction) balancer_status() From 39023ac58180ac94217471e736e26741340c5847 Mon Sep 17 00:00:00 2001 From: Vladislav Nazarenko Date: Wed, 16 Apr 2014 16:17:46 +0200 Subject: [PATCH 05/13] upd: minor formatting changes --- balancer-manage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balancer-manage.py b/balancer-manage.py index 27c3212..2b0ce16 100755 --- a/balancer-manage.py +++ b/balancer-manage.py @@ -97,7 +97,6 @@ def handle_endtag(self, tag): p.feed(f.read()) template = " {Worker:40} | {Status:10} | {Elected:10} | {To:10} | {From:10}" - print template.format(Worker="Worker",Status="Status",Elected="Elected", To="To", From="From") for v in p.datas: r = urlparse(v[0]) @@ -131,6 +130,7 @@ def balancer_manage(sAction, worker): balancer_status() +############################################################################# if __name__ == "__main__": #if ARGS.list is not None: From dac91124ad9630d528a7e02cb2af2932e363957a Mon Sep 17 00:00:00 2001 From: Vladislav Nazarenko Date: Wed, 16 Apr 2014 16:20:56 +0200 Subject: [PATCH 06/13] upd: readme --- README.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 1aaaf4e..577ed17 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Scripts Apache #balancer-manager.py - Allow you to manage Worker/BalancerMember defined in your apache2 mod_proxy conf : + Allow you to manage Worker/BalancerMember defined in your apache2 mod_proxy conf : ```bash @@ -27,18 +27,10 @@ Like : ``` -Fix if necessary : -```bash -#vhostname -headers = {"Host": '127.0.0.1' } -#ip to reach apache -url="http://127.0.0.1/balancer-manager" -``` - - ##Dependency ```bash apt-get install python-argparse + yum install python-argparse ``` ##Example of use: From fa6701eeaffbae307157efb94e444e9d02009ed0 Mon Sep 17 00:00:00 2001 From: Vladislav Nazarenko Date: Wed, 23 Apr 2014 14:53:41 +0200 Subject: [PATCH 07/13] added manage-jk-balancer.py --- manage-jk-balancer.py | 220 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100755 manage-jk-balancer.py diff --git a/manage-jk-balancer.py b/manage-jk-balancer.py new file mode 100755 index 0000000..74301b7 --- /dev/null +++ b/manage-jk-balancer.py @@ -0,0 +1,220 @@ +#!/usr/bin/python -O +# +# Author: Vladislav Nazarenko +# Source: https://github.com/talset/apache-tools +# +# +# File: httpd.conf +# +# JkWorkersFile /etc/httpd/conf.d/workers.properties +# JkLogFile "| /usr/sbin/rotatelogs -l /var/log/httpd/mod_jk-%Y-%m-%d.%H.log 3600" +# JkLogLevel error +# JkLogStampFormat "[%a %b %d %H:%M:%S %Y]" +# JkOptions +ForwardKeySize -ForwardDirectories +ForwardURICompatUnparsed +# JkShmFile [PATH]../jk.shm +# JkMount /jkstatus/* status +# JkMount /* [BALANCER NAME] +# +# File: workers.properties +# +# worker.status.type=status +# +# worker.template.type=ajp13 +# worker.template.socket_timeout=180 +# worker.template.socket_connect_timeout=5000 +# worker.template.retries=2 +# worker.template.recovery_options=3 +# worker.template.distance=0 +# +# worker.appsrvA0.reference=worker.template +# worker.appsrvA0.host=appa01.e.ol.dvag.com +# worker.appsrvA0.port=23009 +# worker.appsrvA1.reference=worker.template +# worker.appsrvA1.host=appa01.e.ol.dvag.com +# worker.appsrvA1.port=23109 +# worker.appsrvB0.reference=worker.template +# worker.appsrvB0.host=appa02.e.ol.dvag.com +# worker.appsrvB0.port=23009 +# worker.appsrvB1.reference=worker.template +# worker.appsrvB1.host=appa02.e.ol.dvag.com +# worker.appsrvB1.port=23109 +# +# worker.appsrv.type=lb +# worker.appsrv.method=B +# worker.appsrv.recover_time=30 +# worker.appsrv.balance_workers=appsrvA0 appsrvA1 appsrvB0 appsrvB1 +# +# worker.list=status appsrv +# +# +# You have to allow /jkstatus +# +# +# Order deny,allow +# Deny from all +# Allow from localhost 127.0.0.1 +# +# +# Verify url="http....." +# +# +# HOW TO : +# balancer-manager.py -l +# balancer-manager.py -w ajp://10.152.45.1:8001 -a enable +# +############################################################################# + +import argparse +import re +import HTMLParser +import sys + +from urllib import urlencode +from urllib2 import Request +from urllib2 import urlopen +from urlparse import urlparse + +############################################################################# +# Get args +PARSER = argparse.ArgumentParser() +PARSER.add_argument("-H", "--host", help="Host connect to", type=str) +PARSER.add_argument("-p", "--port", help="Port connect to", type=str) +PARSER.add_argument("-l", "--list", + help="List Worker member and status", action='store_true') +PARSER.add_argument("-a", "--action", + help="\"enable\" or \"disable\" the specified Worker", type=str) +PARSER.add_argument("-w", "--worker", + help="Worker name : example ajp://127.0.0.1:8001", type=str) +ARGS = PARSER.parse_args() + +############################################################################# +# default values + +host='localhost' +port = 80 + +if ARGS.host: + host = ARGS.host + if ARGS.port: port = ARGS.port + +if ARGS.port: + port = ARGS.port + +url="http://%s:%s/jkstatus/" % (host, port) + +############################################################################# +# functions + +def getWorkersList(): + + reqUrl = "%s?cmd=list" % (url) + req = Request(reqUrl, None) + f = urlopen(req) + #print f.read() + + class TableParser(HTMLParser.HTMLParser): + def __init__(self): + self.datas=[] + self._tds=[] + HTMLParser.HTMLParser.__init__(self) + self.in_td = False + + def handle_starttag(self, tag, attrs): + if tag == 'td' or tag == 'th' or tag == 'h3': + #if tag == 'h4': + self.in_td = True + + def handle_data(self, data): + if self.in_td: + self._tds.append(data) + + def handle_endtag(self, tag): + self.in_td = False + if tag == 'tr' or tag == 'h3': + self.datas.append(self._tds) + self._tds = [] + + + p = TableParser() + p.feed(f.read()) + + balancer = p.datas[20][0] + result = re.search("URI Mappings for ([a-zA-Z0-9]+)", balancer) + if result is not None: + balancer = result.group(1) + else: + print "Could not extract balancer name" + return 1 + + workers = {} + for i in p.datas[10:14]: workers[i[0]] = i[1:] + for i in p.datas[15:19]: workers[i[2]] = workers[i[2]] + i[3:] + + state = {} + for s in workers.keys(): + #print s, workers[s] + a = "%s://%s:%s" % (workers[s][0], workers[s][1],workers[s][2].split(':')[1]) + b = ('enabled', 'disabled')[workers[s][10]=='DIS'] + state[s] = [a, b, balancer] + + return state + + +def balancer_status(): + + state = getWorkersList() + + template = " {Worker:40} | {Status:10}" + print template.format(Worker="Worker",Status="Status") + for k in sorted(state.keys()): + print template.format(Worker=state[k][0],Status=state[k][1]) + template.format(Worker=state[k][0],Status=state[k][1]) + + +def balancer_manage(sAction, worker): + + if sAction not in ['enable', 'disable']: + print "Unknown action: %s" %(sAction) + return 1 + + state = getWorkersList() + + found = False + for k in state.keys(): + + if state[k][0] == worker: + found = True + + r = urlparse(state[k][0]) + print r + if r.scheme: + # the URL is parsable + + action = (0,1)[sAction == 'disable'] + balancer = state[k][2] + + params = urlencode({'cmd': 'update', 'from': 'list','w': balancer, 'sw': k, 'vwa': action}) + req = Request(url+"?%s" % params, None) + urlopen(req) + + print "Action\n Worker %s [%s]\n\nStatus" % (worker,sAction) + balancer_status() + else: + print "Could not parse woker URL: %s" %(worker) + return 1 + + if not found: + print "Could not find worker: %s" %(worker) + return 1 + + +############################################################################# + +if __name__ == "__main__": + #if ARGS.list is not None: + if ARGS.list : + balancer_status() + elif ARGS.action and ARGS.worker: + r = balancer_manage(ARGS.action,ARGS.worker) + sys.exit(r) + else : PARSER.print_help() From a0922b8db36a7344a2928ce3143e94a12949be14 Mon Sep 17 00:00:00 2001 From: Vladislav Nazarenko Date: Wed, 23 Apr 2014 15:27:07 +0200 Subject: [PATCH 08/13] upd: readme --- README.md | 74 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 577ed17..eaae289 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,15 @@ apache-tools Scripts Apache -#balancer-manager.py +##Dependency +```bash + apt-get install python-argparse + yum install python-argparse +``` + +##manage-proxy-balancer.py - Allow you to manage Worker/BalancerMember defined in your apache2 mod_proxy conf : + Allows you to manage Worker/BalancerMember defined in your apache2 mod_proxy conf : ```bash @@ -26,16 +32,68 @@ Like : Allow from 127.0.0.1 ``` +##Example of use: +### JK Balancer +```bash + ./manage-jk-balancer.py -l + ./manage-jk-balancer.py -w ajp://10.152.45.1:8001 -a enable +``` +##manage-jk-balancer.py + Allows you to manage Worker/BalancerMember defined in your apache2 mod_proxy conf : -##Dependency ```bash - apt-get install python-argparse - yum install python-argparse + JkWorkersFile /etc/httpd/conf.d/workers.properties + JkLogFile "| /usr/sbin/rotatelogs -l /var/log/httpd/mod_jk-%Y-%m-%d.%H.log 3600" + JkLogLevel error + JkLogStampFormat "[%a %b %d %H:%M:%S %Y]" + JkOptions +ForwardKeySize -ForwardDirectories +ForwardURICompatUnparsed + JkShmFile [PATH]../jk.shm + JkMount /jkstatus/* status + JkMount /* [BALANCER NAME] ``` -##Example of use: +```bash + worker.status.type=status + + worker.template.type=ajp13 + worker.template.socket_timeout=180 + worker.template.socket_connect_timeout=5000 + worker.template.retries=2 + worker.template.recovery_options=3 + worker.template.distance=0 + + worker.appsrvA0.reference=worker.template + worker.appsrvA0.host=appa01.e.ol.dvag.com + worker.appsrvA0.port=23009 + worker.appsrvA1.reference=worker.template + worker.appsrvA1.host=appa01.e.ol.dvag.com + worker.appsrvA1.port=23109 + worker.appsrvB0.reference=worker.template + worker.appsrvB0.host=appa02.e.ol.dvag.com + worker.appsrvB0.port=23009 + worker.appsrvB1.reference=worker.template + worker.appsrvB1.host=appa02.e.ol.dvag.com + worker.appsrvB1.port=23109 + + worker.appsrv.type=lb + worker.appsrv.method=B + worker.appsrv.recover_time=30 + worker.appsrv.balance_workers=appsrvA0 appsrvA1 appsrvB0 appsrvB1 + worker.list=status appsrv +``` + You have to allow /jkstatus +```bash + + Order deny,allow + Deny from all + Allow from localhost 127.0.0.1 + +``` + +##Example of use: +### Proxy Balancer ```bash - ./balancer-manager.py -l - ./balancer-manager.py -w ajp://10.152.45.1:8001 -a enable + ./manage-proxy-balancer.py -l + ./manage-proxy-balancer.py -w ajp://10.152.45.1:8001 -a enable ``` From 9558fe22cd93596227ad9147443665f3d470650d Mon Sep 17 00:00:00 2001 From: Vladislav Nazarenko Date: Wed, 23 Apr 2014 15:06:15 +0200 Subject: [PATCH 09/13] renamed balancer-manage.py -> manage-proxy-balancer.py --- balancer-manage.py => manage-proxy-balancer.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) rename balancer-manage.py => manage-proxy-balancer.py (91%) diff --git a/balancer-manage.py b/manage-proxy-balancer.py similarity index 91% rename from balancer-manage.py rename to manage-proxy-balancer.py index 2b0ce16..2c2318b 100755 --- a/balancer-manage.py +++ b/manage-proxy-balancer.py @@ -96,14 +96,19 @@ def handle_endtag(self, tag): p = TableParser() p.feed(f.read()) - template = " {Worker:40} | {Status:10} | {Elected:10} | {To:10} | {From:10}" - print template.format(Worker="Worker",Status="Status",Elected="Elected", To="To", From="From") + state = [] for v in p.datas: r = urlparse(v[0]) if r.scheme: # the URL is parsable - print template.format(Worker=v[0],Status=v[3],Elected=v[4], To=v[5], From=v[6]) - template.format(Worker=v[0],Status=v[3],Elected=v[4], To=v[5], From=v[6]) + state.append( [ v[0], ('enabled','disabled')[ v[4].find('Dis') != -1 ] ]) + + + template = " {Worker:40} | {Status:10}" + print template.format(Worker="Worker",Status="Status") + for v in state: + print template.format(Worker=v[0],Status=v[1]) + template.format(Worker=v[0],Status=v[1]) def balancer_manage(sAction, worker): From 33d6e4f2c0543653c8df8b90ccf3477ee85be0b2 Mon Sep 17 00:00:00 2001 From: Vladislav Nazarenko Date: Tue, 27 May 2014 07:36:16 +0200 Subject: [PATCH 10/13] add: support for multiple balancers (mod_proxy) --- manage-proxy-balancer.py | 97 ++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 24 deletions(-) diff --git a/manage-proxy-balancer.py b/manage-proxy-balancer.py index 2c2318b..385f05c 100755 --- a/manage-proxy-balancer.py +++ b/manage-proxy-balancer.py @@ -30,11 +30,11 @@ import re import HTMLParser import sys +import urlparse from urllib import urlencode from urllib2 import Request from urllib2 import urlopen -from urlparse import urlparse ############################################################################# # Get args @@ -72,44 +72,91 @@ def balancer_status(): f = urlopen(req) #print f.read() - class TableParser(HTMLParser.HTMLParser): + class LBParser(HTMLParser.HTMLParser): def __init__(self): - self.datas=[] + self.workers=[] self._tds=[] + self._wData = None + self._balancer="" HTMLParser.HTMLParser.__init__(self) - self.in_td = False + self.in_td = False def handle_starttag(self, tag, attrs): if tag == 'td' or tag == 'th': self.in_td = True + elif self.in_td and tag == 'a': + self._balancer = self.get_balancer_name(attrs) def handle_data(self, data): if self.in_td: - self._tds.append(data) + self._tds.append(data.lstrip().rstrip()) + self._wData = data def handle_endtag(self, tag): + + # if now text data was enclosed by the tag, handle_data function + # is not called, we have to handle it with a hook + if self.in_td and self._wData == None: + self._tds.append('') + #print "ERROR: %s" % (self.get_starttag_text()) + self._wData = None + + # the tag is closed self.in_td = False + + # try to find the worker status + found = False if tag == 'tr': - self.datas.append(self._tds) + for index, v in enumerate(self._tds): + r = urlparse.urlparse(v) + if r.scheme: + found = True + break + + # the worker status found, init the structure + if found: + worker = {} + worker['Balancer'] = self._balancer + worker['URL'] = self._tds[index + 0] + worker['Route'] = self._tds[index + 1] + worker['RouteRedir'] = self._tds[index + 2] + worker['Factor'] = self._tds[index + 3] + worker['Set'] = self._tds[index + 4] + worker['Status'] = ('enabled','disabled')[ self._tds[index + 5].find('Dis') != -1 ] + worker['Elected'] = self._tds[index + 6] + worker['To'] = self._tds[index + 7] + worker['From'] = self._tds[index + 8] + self.workers.append(worker) + self._tds = [] - p = TableParser() + def get_balancer_name(self, attrs): + '''Just a convinience function ''' + for prop, val in attrs: + if prop == 'href': + # b - balancer name + # w - worker name + # nonce - nonce + parsed = urlparse.urlparse(val) + if parsed.path and parsed.query: + return urlparse.parse_qs(parsed.query)['b'][0] + return 'ERROR' + + p = LBParser() p.feed(f.read()) - state = [] - for v in p.datas: - r = urlparse(v[0]) - if r.scheme: - # the URL is parsable - state.append( [ v[0], ('enabled','disabled')[ v[4].find('Dis') != -1 ] ]) - - - template = " {Worker:40} | {Status:10}" - print template.format(Worker="Worker",Status="Status") - for v in state: - print template.format(Worker=v[0],Status=v[1]) - template.format(Worker=v[0],Status=v[1]) + template = "{Worker:40} | {Route:16} | {Status:10}| {From:8} | {To:8} | {Balancer:80}" + print template.format(Worker="Worker",Route="Route", Status="Status",From='From', To = 'To', Balancer='Balancer') + for v in p.workers: + print template.format( + Worker = v['URL'], + Route = v['Route'], + Status = v['Status'], + From = v['From'], + To = v['To'], + Balancer = v['Balancer'] + ) def balancer_manage(sAction, worker): @@ -119,18 +166,20 @@ def balancer_manage(sAction, worker): #Read informations req = Request(url, None) - f = urlopen(req) + f = urlopen(req) #Find balancer and nonce result = re.search("b=([^&]+)&w="+worker+"&nonce=([^\"]+)", f.read()) if result is not None: balancer = result.group(1) - nonce = result.group(2) + nonce = result.group(2) + #Generate URL action = (0,1)[sAction == 'disable'] params = urlencode({'b': balancer, 'w': worker, 'status_D': action, 'nonce': nonce}) - req = Request(url+"?%s" % params, None) - f = urlopen(req) + req = Request(url+"?%s" % params, None) + f = urlopen(req) + print "Action\n Worker %s [%s]\n\nStatus" % (worker,sAction) balancer_status() From 3734bc05ea7aa0d1ca48f5e1f3110fa7d460f44d Mon Sep 17 00:00:00 2001 From: Vladislav Nazarenko Date: Tue, 27 May 2014 07:36:29 +0200 Subject: [PATCH 11/13] add: support for multiple balancers (mod_jk) --- manage-jk-balancer.py | 206 ++++++++++++++++++++++++++++++------------ 1 file changed, 147 insertions(+), 59 deletions(-) diff --git a/manage-jk-balancer.py b/manage-jk-balancer.py index 74301b7..3dadeb3 100755 --- a/manage-jk-balancer.py +++ b/manage-jk-balancer.py @@ -68,11 +68,11 @@ import re import HTMLParser import sys +import urlparse from urllib import urlencode from urllib2 import Request from urllib2 import urlopen -from urlparse import urlparse ############################################################################# # Get args @@ -110,111 +110,199 @@ def getWorkersList(): reqUrl = "%s?cmd=list" % (url) req = Request(reqUrl, None) f = urlopen(req) - #print f.read() - class TableParser(HTMLParser.HTMLParser): + class LBParser(HTMLParser.HTMLParser): def __init__(self): - self.datas=[] - self._tds=[] + self.workers = {} + self._wData = None + self.datas = [] + self._tds = [] + self._balancer = '' + self.in_td = False + self.in_th = False + self.in_h3 = False + + self.in_bm_declaration = False + self.in_bm_status = False + HTMLParser.HTMLParser.__init__(self) - self.in_td = False def handle_starttag(self, tag, attrs): - if tag == 'td' or tag == 'th' or tag == 'h3': - #if tag == 'h4': + if tag == 'td': self.in_td = True + elif tag == 'th': + self.in_th = True + elif tag == 'h3': + self.in_h3 = True + elif self.in_h3 and not self.in_td and tag == 'a': + b = self.get_balancer_name(attrs) + if b: + self._balancer = b def handle_data(self, data): if self.in_td: self._tds.append(data) + self._wData = data + elif self.in_th and data == 'Address:Port': + self.in_bm_declaration = True + elif self.in_th and data == 'Route': + self.in_bm_status = True def handle_endtag(self, tag): + + # if no text data was enclosed by the tag, handle_data function + # is not called, we have to handle it with a hook + if self.in_td and self._wData == None: + self._tds.append('') + #print "ERROR: %s" % (self.get_starttag_text()) + self._wData = None + self.in_td = False - if tag == 'tr' or tag == 'h3': - self.datas.append(self._tds) - self._tds = [] + self.in_th = False + self.in_h3 = False + + if tag == 'table': + self.in_bm_declaration = False + self.in_bm_status = False + + if tag == 'tr': + if self.in_bm_declaration and self._tds != []: + wName = self._tds[0] + worker = {} + + # first workers table + worker['Type'] = self._tds[1] + worker['Hostname'] = self._tds[2] + worker['Address:Port'] = self._tds[3] + worker['ConnectionPoolTimeout'] = self._tds[4] + worker['ConnectTimeout'] = self._tds[5] + worker['PrepostTimeout'] = self._tds[6] + worker['ReplyTimeout'] = self._tds[7] + worker['Retries'] = self._tds[8] + worker['RecoveryOptions'] = self._tds[9] + worker['MaxPacketSize'] = self._tds[10] + worker['Balancer'] = self._balancer + + self.workers[wName] = worker + + elif self.in_bm_status and self._tds != []: + if len(self._tds) > 1: + # there is a legend table which we do not want to + # look in + wName = self._tds[2] + if self.workers.has_key(wName): + # second workers table + self.workers[wName]['ActConf'] = self._tds[3] + self.workers[wName]['State'] = self._tds[4] + self.workers[wName]['Distance'] = self._tds[5] + self.workers[wName]['Factor'] = self._tds[6] + self.workers[wName]['Multiplicity'] = self._tds[7] + self.workers[wName]['Value'] = self._tds[8] + self.workers[wName]['ReqNr'] = self._tds[9] + self.workers[wName]['SessNr'] = self._tds[10] + self.workers[wName]['ErrNr'] = self._tds[11] + self.workers[wName]['ClinetErrNr'] = self._tds[12] + self.workers[wName]['RyplyTO'] = self._tds[13] + self.workers[wName]['BytesWr'] = self._tds[14] + self.workers[wName]['BytesRead'] = self._tds[15] + self.workers[wName]['BusyConnNr'] = self._tds[16] + self.workers[wName]['BusyConnMaxNr'] = self._tds[17] + self.workers[wName]['BackendConnNr'] = self._tds[18] + self.workers[wName]['Route'] = self._tds[19] + self.workers[wName]['RouteRedirect'] = self._tds[20] + self.workers[wName]['ClusterDomain'] = self._tds[21] + self.workers[wName]['RecoverySched'] = self._tds[22] + self.workers[wName]['LastReset'] = self._tds[23] + self.workers[wName]['LastErr'] = self._tds[24] + else: + print "ERROR: could not find worker name in the status table" + self._tds = [] - p = TableParser() - p.feed(f.read()) + def get_balancer_name(self, attrs): + '''Just a convinience function''' + for prop, val in attrs: + if prop == 'href': + # extract balancer name from the query string + parsed = urlparse.urlparse(val) - balancer = p.datas[20][0] - result = re.search("URI Mappings for ([a-zA-Z0-9]+)", balancer) - if result is not None: - balancer = result.group(1) - else: - print "Could not extract balancer name" - return 1 + if parsed.path and parsed.query: + r = urlparse.parse_qs(parsed.query) + if r.has_key('w'): + return r['w'][0] + return False - workers = {} - for i in p.datas[10:14]: workers[i[0]] = i[1:] - for i in p.datas[15:19]: workers[i[2]] = workers[i[2]] + i[3:] - state = {} - for s in workers.keys(): - #print s, workers[s] - a = "%s://%s:%s" % (workers[s][0], workers[s][1],workers[s][2].split(':')[1]) - b = ('enabled', 'disabled')[workers[s][10]=='DIS'] - state[s] = [a, b, balancer] + p = LBParser() + p.feed(f.read()) - return state + return p.workers def balancer_status(): - state = getWorkersList() + workers = getWorkersList() + + if workers: + template = "{Worker:40} | {Route:16} | {Status:10}| {From:16} | {To:16} | {Balancer:80}" + # print workers.keys() + print template.format( Worker="Worker", Route="Route", Status="Status", From='From', To = 'To', Balancer='Balancer' ) - template = " {Worker:40} | {Status:10}" - print template.format(Worker="Worker",Status="Status") - for k in sorted(state.keys()): - print template.format(Worker=state[k][0],Status=state[k][1]) - template.format(Worker=state[k][0],Status=state[k][1]) + for k in sorted(workers.keys()): + # print workers[k] + print template.format( + Worker = "%s://%s:%s" % (workers[k]['Type'], workers[k]['Hostname'], workers[k]['Address:Port'].split(':')[1]), + Route = workers[k]['Route'], + Status = workers[k]['ActConf'], + From = workers[k]['BytesRead'], + To = workers[k]['BytesWr'], + Balancer = workers[k]['Balancer'] + ) + return True + + return False def balancer_manage(sAction, worker): if sAction not in ['enable', 'disable']: print "Unknown action: %s" %(sAction) - return 1 + return False - state = getWorkersList() + workers = getWorkersList() found = False - for k in state.keys(): + for k in workers.keys(): - if state[k][0] == worker: + if worker == "%s://%s:%s" % (workers[k]['Type'], workers[k]['Hostname'], workers[k]['Address:Port'].split(':')[1]): found = True - r = urlparse(state[k][0]) - print r - if r.scheme: - # the URL is parsable - - action = (0,1)[sAction == 'disable'] - balancer = state[k][2] + action = (0,1)[sAction == 'disable'] + balancer = workers[k]['Balancer'] - params = urlencode({'cmd': 'update', 'from': 'list','w': balancer, 'sw': k, 'vwa': action}) - req = Request(url+"?%s" % params, None) - urlopen(req) + params = urlencode({'cmd': 'update', 'from': 'list','w': balancer, 'sw': k, 'vwa': action}) + req = Request(url+"?%s" % params, None) + urlopen(req) - print "Action\n Worker %s [%s]\n\nStatus" % (worker,sAction) - balancer_status() - else: - print "Could not parse woker URL: %s" %(worker) - return 1 + print "Action\n Worker %s [%s]\n\nStatus" % (worker,sAction) + balancer_status() if not found: print "Could not find worker: %s" %(worker) - return 1 + return False ############################################################################# +r = 0 + if __name__ == "__main__": #if ARGS.list is not None: if ARGS.list : - balancer_status() + r = balancer_status() elif ARGS.action and ARGS.worker: r = balancer_manage(ARGS.action,ARGS.worker) - sys.exit(r) - else : PARSER.print_help() + else: + PARSER.print_help() + + sys.exit( not r ) From 9bb68fdaf27f95ca7974dcc5d0206fba6d64baba Mon Sep 17 00:00:00 2001 From: Vladislav Nazarenko Date: Tue, 27 May 2014 07:44:23 +0200 Subject: [PATCH 12/13] upd: description/comments --- README.md | 26 +++++++++++++------------- manage-jk-balancer.py | 26 +++++++++++++------------- manage-proxy-balancer.py | 2 +- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index eaae289..a394aa7 100644 --- a/README.md +++ b/README.md @@ -62,23 +62,23 @@ Like : worker.template.recovery_options=3 worker.template.distance=0 - worker.appsrvA0.reference=worker.template - worker.appsrvA0.host=appa01.e.ol.dvag.com - worker.appsrvA0.port=23009 - worker.appsrvA1.reference=worker.template - worker.appsrvA1.host=appa01.e.ol.dvag.com - worker.appsrvA1.port=23109 - worker.appsrvB0.reference=worker.template - worker.appsrvB0.host=appa02.e.ol.dvag.com - worker.appsrvB0.port=23009 - worker.appsrvB1.reference=worker.template - worker.appsrvB1.host=appa02.e.ol.dvag.com - worker.appsrvB1.port=23109 + worker.appsrv00.reference=worker.template + worker.appsrv00.host=app01.example.com + worker.appsrv00.port=8080 + worker.appsrv01.reference=worker.template + worker.appsrv01.host=app01.example.com + worker.appsrv01.port=9080 + worker.appsrv10.reference=worker.template + worker.appsrv10.host=app02.example.com + worker.appsrv10.port=8080 + worker.appsrv11.reference=worker.template + worker.appsrv11.host=app02.example.com + worker.appsrv11.port=9080 worker.appsrv.type=lb worker.appsrv.method=B worker.appsrv.recover_time=30 - worker.appsrv.balance_workers=appsrvA0 appsrvA1 appsrvB0 appsrvB1 + worker.appsrv.balance_workers=appsrv00 appsrv01 appsrv10 appsrv11 worker.list=status appsrv ``` diff --git a/manage-jk-balancer.py b/manage-jk-balancer.py index 3dadeb3..7fe40cc 100755 --- a/manage-jk-balancer.py +++ b/manage-jk-balancer.py @@ -26,23 +26,23 @@ # worker.template.recovery_options=3 # worker.template.distance=0 # -# worker.appsrvA0.reference=worker.template -# worker.appsrvA0.host=appa01.e.ol.dvag.com -# worker.appsrvA0.port=23009 -# worker.appsrvA1.reference=worker.template -# worker.appsrvA1.host=appa01.e.ol.dvag.com -# worker.appsrvA1.port=23109 -# worker.appsrvB0.reference=worker.template -# worker.appsrvB0.host=appa02.e.ol.dvag.com -# worker.appsrvB0.port=23009 -# worker.appsrvB1.reference=worker.template -# worker.appsrvB1.host=appa02.e.ol.dvag.com -# worker.appsrvB1.port=23109 +# worker.appsrv00.reference=worker.template +# worker.appsrv00.host=app01.example.com +# worker.appsrv00.port=8080 +# worker.appsrv01.reference=worker.template +# worker.appsrv01.host=app01.example.com +# worker.appsrv01.port=9080 +# worker.appsrv10.reference=worker.template +# worker.appsrv10.host=app02.example.com +# worker.appsrv10.port=8080 +# worker.appsrv11.reference=worker.template +# worker.appsrv11.host=app02.example.com +# worker.appsrv11.port=9080 # # worker.appsrv.type=lb # worker.appsrv.method=B # worker.appsrv.recover_time=30 -# worker.appsrv.balance_workers=appsrvA0 appsrvA1 appsrvB0 appsrvB1 +# worker.appsrv.balance_workers=appsrv00 appsrv01 appsrv00 appsrv01 # # worker.list=status appsrv # diff --git a/manage-proxy-balancer.py b/manage-proxy-balancer.py index 385f05c..2560ce9 100755 --- a/manage-proxy-balancer.py +++ b/manage-proxy-balancer.py @@ -94,7 +94,7 @@ def handle_data(self, data): def handle_endtag(self, tag): - # if now text data was enclosed by the tag, handle_data function + # if no text data was enclosed by the tag, handle_data function # is not called, we have to handle it with a hook if self.in_td and self._wData == None: self._tds.append('') From f837cb2d6d537f82b4efbca085a4e8b1e46b3a19 Mon Sep 17 00:00:00 2001 From: Vladislav Nazarenko Date: Tue, 5 Aug 2014 07:35:24 +0200 Subject: [PATCH 13/13] fix: manage-proxy-balancer.py is working again --- manage-proxy-balancer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manage-proxy-balancer.py b/manage-proxy-balancer.py index 2560ce9..4edf6f1 100755 --- a/manage-proxy-balancer.py +++ b/manage-proxy-balancer.py @@ -175,8 +175,8 @@ def balancer_manage(sAction, worker): nonce = result.group(2) #Generate URL - action = (0,1)[sAction == 'disable'] - params = urlencode({'b': balancer, 'w': worker, 'status_D': action, 'nonce': nonce}) + action = sAction + params = urlencode({'b': balancer, 'w': worker, 'dw': action, 'nonce': nonce}) req = Request(url+"?%s" % params, None) f = urlopen(req)