Fix SSL Parsing; Changed all tests;
This commit is contained in:
parent
ddfa2e34ae
commit
74413882fa
6 changed files with 169 additions and 36 deletions
|
|
@ -2,8 +2,7 @@ import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
import json
|
import json
|
||||||
import time
|
import os
|
||||||
|
|
||||||
|
|
||||||
class DockerLabelHandler:
|
class DockerLabelHandler:
|
||||||
def __init__(self, label):
|
def __init__(self, label):
|
||||||
|
|
@ -34,9 +33,12 @@ class DockerLabelHandler:
|
||||||
|
|
||||||
|
|
||||||
class HaproxyConfigGenerator:
|
class HaproxyConfigGenerator:
|
||||||
def __init__(self, mapping):
|
def __init__(self, mapping, ssl_cert_folder="/etc/haproxy/certs"):
|
||||||
self.mapping = mapping
|
self.mapping = mapping
|
||||||
self.label = DockerLabelHandler("com.byjg.easyhaproxy")
|
self.label = DockerLabelHandler("com.byjg.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, lineList = []):
|
def generate(self, lineList = []):
|
||||||
|
|
@ -89,14 +91,13 @@ class HaproxyConfigGenerator:
|
||||||
"80"
|
"80"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
hash = ""
|
||||||
if self.label.create(["sslcert", definition]) in d:
|
if self.label.create(["sslcert", definition]) in d:
|
||||||
hash = hashlib.md5(
|
hash = hashlib.md5(
|
||||||
d[self.label.create(["sslcert", definition])].encode('utf-8')
|
d[self.label.create(["sslcert", definition])].encode('utf-8')
|
||||||
).hexdigest()
|
).hexdigest()
|
||||||
else:
|
|
||||||
hash = ""
|
|
||||||
|
|
||||||
key = port+hash
|
key = port if not hash else port + "_" + hash
|
||||||
|
|
||||||
if key not in easymapping:
|
if key not in easymapping:
|
||||||
easymapping[key] = {
|
easymapping[key] = {
|
||||||
|
|
@ -123,8 +124,9 @@ class HaproxyConfigGenerator:
|
||||||
# handle SSL
|
# handle SSL
|
||||||
ssl_label = self.label.create(["sslcert", definition])
|
ssl_label = self.label.create(["sslcert", definition])
|
||||||
if self.label.has_label(ssl_label):
|
if self.label.has_label(ssl_label):
|
||||||
filename = "/etc/haproxy/certs/{}.{}.pem".format(
|
self.ssl_cert_increment += 1
|
||||||
d[ssl_label], str(time.time())
|
filename = "{}/{}.{}.pem".format(
|
||||||
|
self.ssl_cert_folder, d[host_label], str(self.ssl_cert_increment)
|
||||||
)
|
)
|
||||||
easymapping[key]["ssl_cert"] = filename
|
easymapping[key]["ssl_cert"] = filename
|
||||||
with open(filename, 'wb') as file:
|
with open(filename, 'wb') as file:
|
||||||
|
|
|
||||||
12
tests/expected/no-services.txt
Normal file
12
tests/expected/no-services.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
global
|
||||||
|
log stdout format raw local0 info
|
||||||
|
maxconn 2000
|
||||||
|
tune.ssl.default-dh-param 2048
|
||||||
|
|
||||||
|
defaults
|
||||||
|
log global
|
||||||
|
|
||||||
|
timeout connect 3s
|
||||||
|
timeout client 10s
|
||||||
|
timeout server 10m
|
||||||
|
|
||||||
26
tests/expected/services-tcp.txt
Normal file
26
tests/expected/services-tcp.txt
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
global
|
||||||
|
log stdout format raw local0 info
|
||||||
|
maxconn 2000
|
||||||
|
tune.ssl.default-dh-param 2048
|
||||||
|
|
||||||
|
defaults
|
||||||
|
log global
|
||||||
|
|
||||||
|
timeout connect 3s
|
||||||
|
timeout client 10s
|
||||||
|
timeout server 10m
|
||||||
|
|
||||||
|
|
||||||
|
frontend tcp_in_31339_1
|
||||||
|
bind *:31339
|
||||||
|
mode tcp
|
||||||
|
option tcplog
|
||||||
|
log global
|
||||||
|
default_backend srv_agent_quantum_local_31339_1
|
||||||
|
|
||||||
|
backend srv_agent_quantum_local_31339_1
|
||||||
|
balance roundrobin
|
||||||
|
mode tcp
|
||||||
|
option tcp-check
|
||||||
|
tcp-check connect ssl
|
||||||
|
server srv test_agent:9001 check weight 1 verify none
|
||||||
95
tests/expected/services.txt
Normal file
95
tests/expected/services.txt
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
global
|
||||||
|
log stdout format raw local0 info
|
||||||
|
maxconn 2000
|
||||||
|
tune.ssl.default-dh-param 2048
|
||||||
|
|
||||||
|
defaults
|
||||||
|
log global
|
||||||
|
|
||||||
|
timeout connect 3s
|
||||||
|
timeout client 10s
|
||||||
|
timeout server 10m
|
||||||
|
|
||||||
|
|
||||||
|
frontend tcp_in_31339_1
|
||||||
|
bind *:31339
|
||||||
|
mode tcp
|
||||||
|
option tcplog
|
||||||
|
log global
|
||||||
|
default_backend srv_agent_quantum_example_org_31339_1
|
||||||
|
|
||||||
|
backend srv_agent_quantum_example_org_31339_1
|
||||||
|
balance roundrobin
|
||||||
|
mode tcp
|
||||||
|
option tcp-check
|
||||||
|
tcp-check connect
|
||||||
|
server srv my-stack_agent:9001 check weight 1
|
||||||
|
|
||||||
|
frontend http_in_31337_2
|
||||||
|
bind *:31337
|
||||||
|
mode http
|
||||||
|
|
||||||
|
acl is_rule_cadvisor_quantum_example_org_31337_2_1 hdr(host) -i cadvisor.quantum.example.org
|
||||||
|
acl is_rule_cadvisor_quantum_example_org_31337_2_2 hdr(host) -i cadvisor.quantum.example.org:31337
|
||||||
|
use_backend srv_cadvisor_quantum_example_org_31337_2 if is_rule_cadvisor_quantum_example_org_31337_2_1 OR is_rule_cadvisor_quantum_example_org_31337_2_2
|
||||||
|
|
||||||
|
acl is_rule_node-exporter_quantum_example_org_31337_2_1 hdr(host) -i node-exporter.quantum.example.org
|
||||||
|
acl is_rule_node-exporter_quantum_example_org_31337_2_2 hdr(host) -i node-exporter.quantum.example.org:31337
|
||||||
|
use_backend srv_node-exporter_quantum_example_org_31337_2 if is_rule_node-exporter_quantum_example_org_31337_2_1 OR is_rule_node-exporter_quantum_example_org_31337_2_2
|
||||||
|
|
||||||
|
backend srv_cadvisor_quantum_example_org_31337_2
|
||||||
|
balance roundrobin
|
||||||
|
mode http
|
||||||
|
option forwardfor
|
||||||
|
http-request set-header X-Forwarded-Port %[dst_port]
|
||||||
|
http-request add-header X-Forwarded-Proto https if { ssl_fc }
|
||||||
|
server srv my-stack_cadvisor:8080 check weight 1
|
||||||
|
backend srv_node-exporter_quantum_example_org_31337_2
|
||||||
|
balance roundrobin
|
||||||
|
mode http
|
||||||
|
option forwardfor
|
||||||
|
http-request set-header X-Forwarded-Port %[dst_port]
|
||||||
|
http-request add-header X-Forwarded-Proto https if { ssl_fc }
|
||||||
|
server srv my-stack_node-exporter:9100 check weight 1
|
||||||
|
|
||||||
|
frontend http_in_80_3
|
||||||
|
bind *:80
|
||||||
|
mode http
|
||||||
|
redirect prefix https://www.somehost.com.br code 301 if { hdr(host) -i somehost.com.br }
|
||||||
|
redirect prefix https://www.somehost.com.br code 301 if { hdr(host) -i somehost.com }
|
||||||
|
redirect prefix https://www.somehost.com.br code 301 if { hdr(host) -i www.somehost.com }
|
||||||
|
redirect prefix https://www.somehost.com.br code 301 if { hdr(host) -i byjg.ca }
|
||||||
|
redirect prefix https://www.somehost.com.br code 301 if { hdr(host) -i www.byjg.ca }
|
||||||
|
|
||||||
|
acl is_rule_www_somehost_com_br_80_3_1 hdr(host) -i www.somehost.com.br
|
||||||
|
acl is_rule_www_somehost_com_br_80_3_2 hdr(host) -i www.somehost.com.br:80
|
||||||
|
use_backend srv_www_somehost_com_br_80_3 if is_rule_www_somehost_com_br_80_3_1 OR is_rule_www_somehost_com_br_80_3_2
|
||||||
|
|
||||||
|
backend srv_www_somehost_com_br_80_3
|
||||||
|
balance roundrobin
|
||||||
|
mode http
|
||||||
|
option forwardfor
|
||||||
|
http-request set-header X-Forwarded-Port %[dst_port]
|
||||||
|
http-request add-header X-Forwarded-Proto https if { ssl_fc }
|
||||||
|
server srv some-service:80 check weight 1
|
||||||
|
|
||||||
|
frontend http_in_443_4
|
||||||
|
bind *:443 ssl crt /tmp/www.somehost.com.br.1.pem
|
||||||
|
mode http
|
||||||
|
redirect prefix https://www.somehost.com.br code 301 if { hdr(host) -i somehost.com.br }
|
||||||
|
redirect prefix https://www.somehost.com.br code 301 if { hdr(host) -i somehost.com }
|
||||||
|
redirect prefix https://www.somehost.com.br code 301 if { hdr(host) -i www.somehost.com }
|
||||||
|
redirect prefix https://www.somehost.com.br code 301 if { hdr(host) -i byjg.ca }
|
||||||
|
redirect prefix https://www.somehost.com.br code 301 if { hdr(host) -i www.byjg.ca }
|
||||||
|
|
||||||
|
acl is_rule_www_somehost_com_br_443_4_1 hdr(host) -i www.somehost.com.br
|
||||||
|
acl is_rule_www_somehost_com_br_443_4_2 hdr(host) -i www.somehost.com.br:443
|
||||||
|
use_backend srv_www_somehost_com_br_443_4 if is_rule_www_somehost_com_br_443_4_1 OR is_rule_www_somehost_com_br_443_4_2
|
||||||
|
|
||||||
|
backend srv_www_somehost_com_br_443_4
|
||||||
|
balance roundrobin
|
||||||
|
mode http
|
||||||
|
option forwardfor
|
||||||
|
http-request set-header X-Forwarded-Port %[dst_port]
|
||||||
|
http-request add-header X-Forwarded-Proto https if { ssl_fc }
|
||||||
|
server srv some-service:80 check weight 1
|
||||||
1
tests/fixtures/services
vendored
1
tests/fixtures/services
vendored
|
|
@ -3,3 +3,4 @@ my-stack_agent={"com.byjg.easyhaproxy.definitions":"agent","com.byjg.easyhaproxy
|
||||||
my-stack_cadvisor={"com.byjg.easyhaproxy.definitions":"cadvisor","com.byjg.easyhaproxy.host.cadvisor":"cadvisor.quantum.example.org","com.byjg.easyhaproxy.localport.cadvisor":"8080","com.byjg.easyhaproxy.port.cadvisor":"31337","com.docker.stack.image":"gcr.io/google-containers/cadvisor:v0.34.0","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
my-stack_cadvisor={"com.byjg.easyhaproxy.definitions":"cadvisor","com.byjg.easyhaproxy.host.cadvisor":"cadvisor.quantum.example.org","com.byjg.easyhaproxy.localport.cadvisor":"8080","com.byjg.easyhaproxy.port.cadvisor":"31337","com.docker.stack.image":"gcr.io/google-containers/cadvisor:v0.34.0","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
||||||
my-stack_node-exporter={"com.byjg.easyhaproxy.definitions":"exp","com.byjg.easyhaproxy.host.exp":"node-exporter.quantum.example.org","com.byjg.easyhaproxy.localport.exp":"9100","com.byjg.easyhaproxy.port.exp":"31337","com.docker.stack.image":"stefanprodan/swarmprom-node-exporter:v0.16.0","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
my-stack_node-exporter={"com.byjg.easyhaproxy.definitions":"exp","com.byjg.easyhaproxy.host.exp":"node-exporter.quantum.example.org","com.byjg.easyhaproxy.localport.exp":"9100","com.byjg.easyhaproxy.port.exp":"31337","com.docker.stack.image":"stefanprodan/swarmprom-node-exporter:v0.16.0","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
||||||
my-stack_reverse-proxy={"com.docker.stack.image":"quay.io/pngmbh/easy-haproxy:tcp-mode","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
my-stack_reverse-proxy={"com.docker.stack.image":"quay.io/pngmbh/easy-haproxy:tcp-mode","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
||||||
|
some-service={"com.byjg.easyhaproxy.definitions":"http,https","com.byjg.easyhaproxy.port.http":"80","com.byjg.easyhaproxy.host.http":"www.somehost.com.br","com.byjg.easyhaproxy.localport.http":"80","com.byjg.easyhaproxy.redirect.http":"somehost.com.br--https://www.somehost.com.br,somehost.com--https://www.somehost.com.br,www.somehost.com--https://www.somehost.com.br,byjg.ca--https://www.somehost.com.br,www.byjg.ca--https://www.somehost.com.br","com.byjg.easyhaproxy.port.https":"443","com.byjg.easyhaproxy.host.https":"www.somehost.com.br","com.byjg.easyhaproxy.localport.https":"80","com.byjg.easyhaproxy.redirect.https":"somehost.com.br--https://www.somehost.com.br,somehost.com--https://www.somehost.com.br,www.somehost.com--https://www.somehost.com.br,byjg.ca--https://www.somehost.com.br,www.byjg.ca--https://www.somehost.com.br","com.byjg.easyhaproxy.sslcert.https":"U29tZSBQRU0gQ2VydGlmaWNhdGU="}
|
||||||
|
|
@ -19,11 +19,13 @@ def test_parser_doesnt_crash():
|
||||||
"customerrors": False
|
"customerrors": False
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg = easymapping.HaproxyConfigGenerator(result)
|
cfg = easymapping.HaproxyConfigGenerator(result, "/tmp")
|
||||||
haproxy_config = cfg.generate(lineList)
|
haproxy_config = cfg.generate(lineList)
|
||||||
|
|
||||||
assert len(haproxy_config) > 0
|
assert len(haproxy_config) > 0
|
||||||
assert "frontend" not in haproxy_config
|
path = os.path.dirname(os.path.realpath(__file__))
|
||||||
assert "backend" not in haproxy_config
|
with open(path + "/expected/no-services.txt", 'r') as expected_file:
|
||||||
|
assert expected_file.read() == haproxy_config
|
||||||
|
|
||||||
|
|
||||||
def test_parser_finds_services():
|
def test_parser_finds_services():
|
||||||
|
|
@ -33,14 +35,20 @@ def test_parser_finds_services():
|
||||||
"customerrors": False
|
"customerrors": False
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg = easymapping.HaproxyConfigGenerator(result)
|
cert_file = "/tmp/www.somehost.com.br.1.pem"
|
||||||
haproxy_config = cfg.generate(lineList)
|
if os.path.exists(cert_file):
|
||||||
assert len(haproxy_config) > 0
|
os.remove(cert_file)
|
||||||
assert "mode tcp" in haproxy_config
|
|
||||||
assert "mode http" in haproxy_config
|
|
||||||
|
|
||||||
assert "frontend tcp_in_31339_1" in haproxy_config
|
cfg = easymapping.HaproxyConfigGenerator(result, "/tmp")
|
||||||
assert "frontend http_in_31337_2" in haproxy_config
|
haproxy_config = cfg.generate(lineList)
|
||||||
|
|
||||||
|
assert len(haproxy_config) > 0
|
||||||
|
path = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
with open(path + "/expected/services.txt", 'r') as expected_file:
|
||||||
|
assert expected_file.read() == haproxy_config
|
||||||
|
|
||||||
|
with open(cert_file, 'r') as expected_file:
|
||||||
|
assert expected_file.read() == "Some PEM Certificate"
|
||||||
|
|
||||||
|
|
||||||
def test_parser_static():
|
def test_parser_static():
|
||||||
|
|
@ -48,13 +56,14 @@ def test_parser_static():
|
||||||
with open(path + "/fixtures/static.yml", 'r') as content_file:
|
with open(path + "/fixtures/static.yml", 'r') as content_file:
|
||||||
parsed = yaml.load(content_file.read(), Loader=yaml.FullLoader)
|
parsed = yaml.load(content_file.read(), Loader=yaml.FullLoader)
|
||||||
|
|
||||||
cfg = easymapping.HaproxyConfigGenerator(parsed)
|
cfg = easymapping.HaproxyConfigGenerator(parsed, "/tmp")
|
||||||
haproxy_config = cfg.generate()
|
haproxy_config = cfg.generate()
|
||||||
assert len(haproxy_config) > 0
|
assert len(haproxy_config) > 0
|
||||||
|
|
||||||
with open(path + "/expected/static.txt", 'r') as expected_file:
|
with open(path + "/expected/static.txt", 'r') as expected_file:
|
||||||
assert expected_file.read() == haproxy_config
|
assert expected_file.read() == haproxy_config
|
||||||
|
|
||||||
|
|
||||||
def test_parser_tcp():
|
def test_parser_tcp():
|
||||||
lineList = load_fixture("services-tcp")
|
lineList = load_fixture("services-tcp")
|
||||||
|
|
||||||
|
|
@ -62,23 +71,11 @@ def test_parser_tcp():
|
||||||
"customerrors": False
|
"customerrors": False
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg = easymapping.HaproxyConfigGenerator(result)
|
cfg = easymapping.HaproxyConfigGenerator(result, "/tmp")
|
||||||
haproxy_config = cfg.generate(lineList)
|
haproxy_config = cfg.generate(lineList)
|
||||||
# print(haproxy_config)
|
# print(haproxy_config)
|
||||||
|
|
||||||
frontend_cfg = "frontend tcp_in_31339_1\n"
|
assert len(haproxy_config) > 0
|
||||||
frontend_cfg += " bind *:31339\n"
|
path = os.path.dirname(os.path.realpath(__file__))
|
||||||
frontend_cfg += " mode tcp\n"
|
with open(path + "/expected/services-tcp.txt", 'r') as expected_file:
|
||||||
frontend_cfg += " option tcplog\n"
|
assert expected_file.read() == haproxy_config
|
||||||
frontend_cfg += " log global\n"
|
|
||||||
frontend_cfg += " default_backend srv_agent_quantum_local_31339_1\n\n"
|
|
||||||
assert frontend_cfg in haproxy_config
|
|
||||||
|
|
||||||
backend_cfg = "backend srv_agent_quantum_local_31339_1\n"
|
|
||||||
backend_cfg += " balance roundrobin\n"
|
|
||||||
backend_cfg += " mode tcp\n"
|
|
||||||
backend_cfg += " option tcp-check\n"
|
|
||||||
backend_cfg += " tcp-check connect ssl\n"
|
|
||||||
backend_cfg += " server srv test_agent:9001 check weight 1 verify none"
|
|
||||||
|
|
||||||
assert backend_cfg in haproxy_config
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue