Permalink
Cannot retrieve contributors at this time
#!/usr/bin/python | |
# Kubernetes to HA Proxy config updater script | |
# Copyright (C) 2017 Glen Pitt-Pladdy | |
# | |
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation, either version 3 of the License, or | |
# (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
# | |
# | |
# See: https://www.pitt-pladdy.com/blog/_20170328-130720_0100_Kubernetes_to_learn_Part_4/ | |
# | |
import json | |
import subprocess | |
import time | |
import sys | |
import os | |
template = '/etc/haproxy/haproxy.cfg.TEMPLATE' | |
outputcfg = '/etc/haproxy/haproxy.cfg' | |
polldelay = 5 | |
def getnodes(): | |
p = subprocess.Popen ( ['kubectl','get','nodes','-o','json'], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) | |
stdout,stderr = p.communicate() | |
return json.loads ( stdout ) | |
def getservices(): | |
p = subprocess.Popen ( ['kubectl','get','services','-o','json'], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) | |
stdout,stderr = p.communicate() | |
return json.loads ( stdout ) | |
def reloadhaproxy(): | |
p = subprocess.Popen ( ['systemctl','reload','haproxy'], stdout=None, stderr=None ) | |
lastconfig = '' | |
while True: | |
# get all our nodes | |
nodes = [] | |
for node in getnodes()['items']: | |
for state in node['status']['conditions']: | |
if state['type'] == 'Ready' and state['status'] == 'True': | |
# good node - add this | |
for address in node['status']['addresses']: | |
if address['type'] == 'InternalIP': | |
nodes.append ( address['address'] ) | |
break | |
break | |
# ingest all our services | |
services = {} | |
for service in getservices()['items']: | |
if service['spec']['type'] == 'NodePort': | |
app = service['spec']['selector']['app'] | |
if app not in services: services[app] = {} | |
tier = service['spec']['selector']['tier'] | |
if 'tier' not in services: services[app][tier] = {} | |
for portspec in service['spec']['ports']: | |
if portspec['protocol'] != 'TCP': continue # we can't do this | |
services[app][tier][portspec['port']] = portspec['nodePort'] | |
# generate HA Proxy config snipped | |
config = "\n# automatically generated by %s\n\n" % sys.argv[0] | |
portused = {} | |
for app in services: | |
for tier in services[app]: | |
for port in services[app][tier]: | |
# frontend | |
config += "frontend %s_%s\n" % (app,tier) | |
listenport = int(port) | |
while listenport in portused: listenport += 1 | |
portused[listenport] = True | |
config += "\tbind *:%d\n" % listenport | |
config += "\tdefault_backend %s_%s\n" % (app,tier) | |
# backend | |
config += "backend %s_%s\n" % (app,tier) | |
config += "\tbalance roundrobin\n" | |
for node in nodes: | |
config += "\tserver %s %s:%s check\n" % (node.replace('.','_'),node,services[app][tier][port]) | |
if config != lastconfig: | |
print "Configuration Changed!" | |
print config | |
with open ( template, 'rt' ) as fi: | |
with open ( outputcfg+'.TMP', 'wt' ) as fo: | |
fo.write ( fi.read() ) | |
fo.write ( config ) | |
os.rename ( outputcfg+'.TMP', outputcfg ) | |
reloadhaproxy () | |
lastconfig = config | |
time.sleep ( polldelay ) | |