1
0
Fork 0
docker-easy-haproxy/easymapping/__init__.py
2022-08-12 02:01:11 +00:00

151 lines
5 KiB
Python

import base64
import hashlib
from jinja2 import Environment, FileSystemLoader
import json
import os
class DockerLabelHandler:
def __init__(self, label):
self.__label_base = label
def create(self, key):
if isinstance(key, str):
return "{}.{}".format(self.__label_base, key)
return "{}.{}".format(self.__label_base, ".".join(key))
def get(self, label, default_value = ""):
if self.has_label(label):
return self.__data[label]
return default_value
def set_data(self, data):
self.__data = data
def has_label(self, label):
if label in self.__data:
return True
return False
class HaproxyConfigGenerator:
def __init__(self, mapping, ssl_cert_folder="/etc/haproxy/certs"):
self.mapping = mapping
self.label = DockerLabelHandler(mapping['lookup_label'] if 'lookup_label' in mapping else "easyhaproxy")
self.ssl_cert_folder = ssl_cert_folder
self.ssl_cert_increment = 0
os.makedirs(self.ssl_cert_folder, exist_ok=True)
def generate(self, line_list = []):
# static?
if len(line_list) > 0:
self.mapping["easymapping"] = self.parse(line_list)
else:
for d in self.mapping["easymapping"]:
for name, hosts in d.get('hosts', {}).items():
if type(hosts) != list:
d['hosts'][name] = [hosts]
# still 'None' -> default to [] for jinja2
if self.mapping["easymapping"] is None:
self.mapping["easymapping"] = []
file_loader = FileSystemLoader('templates')
env = Environment(loader=file_loader)
env.trim_blocks = True
env.lstrip_blocks = True
env.rstrip_blocks = True
template = env.get_template('haproxy.cfg.j2')
return template.render(data=self.mapping)
def parse(self, line_list):
easymapping = dict()
for line in line_list:
line = line.strip()
i = line.find("=")
container = line[:i]
jsonStr = line[i+1:]
d = json.loads(jsonStr)
if self.label.create("definitions") not in d.keys():
continue
self.label.set_data(d)
definitions = d[self.label.create("definitions")].split(",")
for definition in definitions:
mode = self.label.get(
self.label.create([definition, "mode"]),
"http"
)
# TODO: we can ignore "host" in TCP, but it would break the template
host_label = self.label.create([definition, "host"])
if not self.label.has_label(host_label):
continue
port = self.label.get(
self.label.create([definition, "port"]),
"80"
)
hash = ""
if self.label.create([definition, "sslcert"]) in d:
hash = hashlib.md5(
d[self.label.create([definition, "sslcert"])].encode('utf-8')
).hexdigest()
key = port if not hash else port + "_" + hash
if key not in easymapping:
easymapping[key] = {
"mode": mode,
"health-check": "",
"port": port,
"hosts": dict(),
"redirect": dict(),
}
# TODO: this could use `EXPOSE` from `Dockerfile`?
ct_port = self.label.get(
self.label.create([definition, "localport"]),
"80"
)
easymapping[key]["health-check"] = self.label.get(
self.label.create([definition, "health-check"]),
""
)
easymapping[key]["hosts"].setdefault(d[host_label], [])
easymapping[key]["hosts"][d[host_label]] += ["{}:{}".format(container, ct_port)]
# handle SSL
ssl_label = self.label.create([definition, "sslcert"])
if self.label.has_label(ssl_label):
self.ssl_cert_increment += 1
filename = "{}/{}.{}.pem".format(
self.ssl_cert_folder, d[host_label], str(self.ssl_cert_increment)
)
easymapping[key]["ssl_cert"] = filename
with open(filename, 'wb') as file:
file.write(
base64.b64decode(d[ssl_label])
)
# handle redirects
redirect = self.label.get(
self.label.create([definition, "redirect"])
)
if len(redirect) > 0:
for r in redirect.split(","):
r_parts = r.split("--")
easymapping[key]["redirect"][r_parts[0]] = r_parts[1]
return easymapping.values()