1
0
Fork 0

Merge pull request #4 from pngmbh/tcp-mode

Tcp mode
This commit is contained in:
Joao Gilberto Magalhães 2020-06-07 23:28:11 -05:00 committed by GitHub
commit 82391f0939
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 460 additions and 126 deletions

View file

@ -8,8 +8,6 @@ COPY requirements.txt /scripts
RUN pip3 install --upgrade pip \
&& pip install -r requirements.txt
COPY swarm.* /scripts/
COPY static.* /scripts/
COPY templates /scripts/templates/
COPY easymapping /scripts/easymapping/

7
Makefile Normal file
View file

@ -0,0 +1,7 @@
.PHONY: build
build:
docker build -t byjg/easy-haproxy -t byjg/easy-haproxy:local .
.PHONY: test
test:
pytest tests/

View file

@ -1,24 +1,24 @@
# Easy HAProxy
# Easy HAProxy
This Docker image will create dynamically the `haproxy.cfg` based on the labels defined in docker containers or from
a simple Yaml instead docker
This Docker image will create dynamically the `haproxy.cfg` based on the labels defined in docker containers or from
a simple Yaml instead docker
# Features
- Enable or disable Stats on port 1936 with custom password
- Discover and setup haproxy from Docker Tag
- Discover and setup haproxy from Docker Tag
- Discover and setup haproxy redirect from Docker Tag
- Setup HAProxy CFG from a Yaml file.
- Setup HAProxy CFG from a Yaml file.
# Basic Usage
The Easy HAProxy will create the `haproxy.cfg` automatically based on the containers or from a YAML provided.
The Easy HAProxy will create the `haproxy.cfg` automatically based on the containers or from a YAML provided.
The basic command line to run is:
```bash
docker run -d \
docker run -d \
--name easy-haproxy-container \
-v /var/run/docker.sock:/var/run/docker.sock \
-e DISCOVER="swarm|docker|static" \
@ -29,7 +29,7 @@ docker run -d \
The mapping to `/var/run/docker.sock` is necessary to discover the docker containers and get the labels;
The environment variables will setup the HAProxy.
The environment variables will setup the HAProxy.
{:.table}
| Environment Variable | Description |
@ -49,9 +49,9 @@ The environment variable `DISCOVER` will define where is located your containers
# DISCOVER: docker
This method will use a regular docker installation to discover the containers and configure the HAProxy.
This method will use a regular docker installation to discover the containers and configure the HAProxy.
The only requirement is that containers and easy-haproxy must be in the same docker network.
The only requirement is that containers and easy-haproxy must be in the same docker network.
The discover will occur every minute.
@ -67,12 +67,12 @@ docker run --network easyhaproxy myimage
# DISCOVER: swarm
This method requires a functional Docker Swarm Cluster. The system will search for the labels in all containers on all
swarm nodes.
This method requires a functional Docker Swarm Cluster. The system will search for the labels in all containers on all
swarm nodes.
The discover will occur every minute.
Important: easyhaproxy needs to be in the same network of the containers or otherwise will not access.
Important: easyhaproxy needs to be in the same network of the containers or otherwise will not access.
## Tags to be attached in the Docker Container
@ -80,12 +80,13 @@ Important: easyhaproxy needs to be in the same network of the containers or othe
| Tag | Description |
|---------------------------------------------|---------------------------------------------------------------------------------------------------------|
| com.byjg.easyhaproxy.definitions | A Comma delimited list with the definitions. Each name requires the definition of the parameters below. |
| com.byjg.easyhaproxy.mode.[definition] | (Optional) Is this http or tcp mode in HAProxy. (Defaults to http) |
| com.byjg.easyhaproxy.port.[definition] | (Optional) What is the port that the HAProxy will listen to. (Defaults to 80) |
| com.byjg.easyhaproxy.localport.[definition] | (Optional) What is the port that the container is listening. (Defaults to 80) |
| com.byjg.easyhaproxy.host.[definition] | What is the host that the HAProxy will listen to. |
| com.byjg.easyhaproxy.redirect.[definition] | (Optional) Host redirects from connections in the port defined above. |
| com.byjg.easyhaproxy.sslcert.[definition] | (Optional) Cert PEM Base64 encoded. |
| com.byjg.easyhaproxy.health-check.[definition] | (Optional) `ssl`, enable health check via SSL in `mode tcp` (Defaults to "empty") |
Note: if you are deploying a stack set labels at the `deploy` level:
@ -126,6 +127,22 @@ docker run \
some/myimage
```
### TLS passthrough
Used to pass on SSL-termination to a backend:
```bash
docker run \
-l com.byjg.easyhaproxy.defintions=tcp-service \
-l com.byjg.easyhaproxy.mode.tcp-service=tcp \
-l com.byjg.easyhaproxy.health-check.tcp-service=ssl \
-l com.byjg.easyhaproxy.port.tcp-service=443
.... \
some/tcp-service
```
- enable health-check via SSL on the backend with the optional `health-check` label
### Redirect Example:
```bash
@ -149,12 +166,12 @@ customerrors: true # Optional (default false)
easymapping:
- port: 80
hosts:
hosts:
host1.com.br: container:5000
host2.com.br: other:3000
redirect:
www.host1.com.br: http://host1.com.br
- port: 443
ssl_cert: BASE64_PEM_CERTIFICATE
hosts:
@ -173,10 +190,10 @@ docker run -v /my/config.yml:/etc/haproxy/easyconfig.yml .... byjg/easyhaproxy
# Mapping custom .cfg files
Map a folder containing valid HAProxy `.cfg` files to `/etc/haproxy/conf.d`. It will be concatenated to your HAProxy CFG.
Map a folder containing valid HAProxy `.cfg` files to `/etc/haproxy/conf.d`. It will be concatenated to your HAProxy CFG.
```bash
docker run \
docker run \
/* other parameters */
-v /your/local/conf.d:/etc/haproxy/conf.d \
-d byjg/easy-haproxy
@ -185,9 +202,9 @@ docker run \
# Handling SSL
You can attach a valid SSL certificate to the request.
You can attach a valid SSL certificate to the request.
1. First Create a single PEM file including CA.
1. First Create a single PEM file including CA.
```bash
cat example.com.crt example.com.key > single.pem
@ -215,8 +232,8 @@ cat single.pem | base64 -w0
# Setting Custom Errors
If enabled, map the volume : `/etc/haproxy/errors-custom/` to your container and put a file named `ERROR_NUMBER.http`
where ERROR_NUMBER is the http error code (e.g. 503.http)
If enabled, map the volume : `/etc/haproxy/errors-custom/` to your container and put a file named `ERROR_NUMBER.http`
where ERROR_NUMBER is the http error code (e.g. 503.http)
# Build

View file

@ -18,14 +18,18 @@ else
if [[ "$DISCOVER" == "docker" ]]; then
CONTAINERS=$(docker ps -q)
LABEL_PATH=".Config.Labels"
for container in ${CONTAINERS}; do
docker inspect --format "{{ json $LABEL_PATH }}" ${container} | xargs -I % echo ${container}=% >> ${CONTROL_FILE}
done
else
CONTAINERS=$(docker node ps $(docker node ls -q) --format "{{ .Name }}" --filter desired-state=running | cut -d. -f1 | sort | uniq)
LABEL_PATH=".Spec.Labels"
fi
for container in ${CONTAINERS}; do
docker inspect --format "{{ json $LABEL_PATH }}" ${container} | xargs -I % echo ${container}=% >> ${CONTROL_FILE}
done
for container in ${CONTAINERS}; do
docker service inspect --format "{{ json $LABEL_PATH }}" ${container} | xargs -I % echo ${container}=% >> ${CONTROL_FILE}
done
fi
if cmp -s ${CONTROL_FILE} ${CONTROL_FILE}.old ; then
RELOAD="false"

24
assets/scripts/swarm.py Normal file
View file

@ -0,0 +1,24 @@
import os
from easymapping import HaproxyConfigGenerator
# path = os.path.dirname(os.path.realpath(__file__))
with open("/tmp/.docker_data", 'r') as content_file:
lineList = content_file.readlines()
result = {
"customerrors": True if os.getenv("HAPROXY_CUSTOMERRORS") == "true" else False
}
if os.getenv("HAPROXY_PASSWORD"):
result["stats"] = {
"username": os.getenv("HAPROXY_USERNAME") if os.getenv("HAPROXY_USERNAME") else "admin",
"password": os.getenv("HAPROXY_PASSWORD"),
"port": os.getenv("HAPROXY_STATS_PORT") if os.getenv("HAPROXY_STATS_PORT") else "1936",
}
cfg = HaproxyConfigGenerator(result)
print(cfg.generate(lineList))
# print(jsonStr)

View file

@ -1,12 +1,144 @@
import base64
import hashlib
from jinja2 import Environment, FileSystemLoader
import json
import time
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):
self.mapping = mapping
self.label = DockerLabelHandler("com.byjg.easyhaproxy")
def generate(self, lineList = []):
# static?
if len(lineList) > 0:
self.mapping["easymapping"] = self.__parse(lineList)
# still 'None' -> default to [] for jinja2
if self.mapping["easymapping"] is None:
self.mapping["easymapping"] = []
def generate(self):
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, lineList):
easymapping = dict()
for line in lineList:
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(["mode", definition]),
"http"
)
# TODO: we can ignore "host" in TCP, but it would break the template
host_label = self.label.create(["host", definition])
if not self.label.has_label(host_label):
continue
port = self.label.get(
self.label.create(["port", definition]),
"80"
)
if self.label.create(["sslcert", definition]) in d:
hash = hashlib.md5(
d[self.label.create(["sslcert", definition])].encode('utf-8')
).hexdigest()
else:
hash = ""
key = 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(["localport", definition]),
"80"
)
easymapping[key]["health-check"] = self.label.get(
self.label.create(["health-check", definition]),
""
)
easymapping[key]["hosts"][d[host_label]] = "{}:{}".format(container, ct_port)
# handle SSL
ssl_label = self.label.create(["sslcert", definition])
if self.label.has_label(ssl_label):
filename = "/etc/haproxy/certs/{}.{}.pem".format(
d[ssl_label], str(time.time())
)
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(["redirect", definition])
)
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()

2
pytest.ini Normal file
View file

@ -0,0 +1,2 @@
[pytest]
addopts = -v -p no:warnings

20
setup.py Normal file
View file

@ -0,0 +1,20 @@
from setuptools import setup, find_packages
with open('README.md') as f:
readme = f.read()
with open('LICENSE') as f:
license = f.read()
setup(
name='easymapping',
version='0.1.0',
description='HAProxy label based routing',
long_description=readme,
author='',
author_email='',
url='',
license=license,
packages=find_packages(exclude=('tests', 'docs'))
)

View file

@ -1,74 +0,0 @@
import os
import json
import time
import base64
import hashlib
from easymapping import HaproxyConfigGenerator
# path = os.path.dirname(os.path.realpath(__file__))
with open("/tmp/.docker_data", 'r') as content_file:
lineList = content_file.readlines()
result = {
"easymapping": [],
"customerrors": True if os.getenv("HAPROXY_CUSTOMERRORS") == "true" else False
}
easymapping = dict()
if os.getenv("HAPROXY_PASSWORD"):
result["stats"] = {
"username": os.getenv("HAPROXY_USERNAME") if os.getenv("HAPROXY_USERNAME") else "admin",
"password": os.getenv("HAPROXY_PASSWORD"),
"port": os.getenv("HAPROXY_STATS_PORT") if os.getenv("HAPROXY_STATS_PORT") else "1936",
}
for line in lineList:
line = line.strip()
i = line.find("=")
container = line[:i]
jsonStr = line[i+1:]
d = json.loads(jsonStr)
if "com.byjg.easyhaproxy.definitions" in d.keys():
definitions = d["com.byjg.easyhaproxy.definitions"].split(",")
for definition in definitions:
if "com.byjg.easyhaproxy.host." + definition not in d:
continue
port = d["com.byjg.easyhaproxy.port." + definition] if "com.byjg.easyhaproxy.port." + definition in d else "80"
hash = hashlib.md5(d["com.byjg.easyhaproxy.sslcert." + definition].encode('utf-8')).hexdigest() if "com.byjg.easyhaproxy.sslcert." + definition in d else ""
key = port+hash
if key not in easymapping:
easymapping[key] = {
"port": port,
"hosts": dict(),
"redirect": dict(),
# "ssl_cert": ""
}
easymapping[key]["hosts"][d["com.byjg.easyhaproxy.host." + definition]] = container + ":" + (d["com.byjg.easyhaproxy.localport." + definition] if "com.byjg.easyhaproxy.localport." + definition in d else "80")
if "com.byjg.easyhaproxy.sslcert." + definition in d:
filename = '/etc/haproxy/certs/' + d["com.byjg.easyhaproxy.host." + definition] + "." + str(time.time()) + ".pem"
easymapping[key]["ssl_cert"] = filename
with open(filename, 'wb') as file:
file.write(base64.b64decode(d["com.byjg.easyhaproxy.sslcert." + definition]))
if "com.byjg.easyhaproxy.redirect." + definition in d:
redirect = d["com.byjg.easyhaproxy.redirect." + definition] if "com.byjg.easyhaproxy.redirect." + definition in d else ""
for r in redirect.split(","):
r_parts = r.split("--")
easymapping[key]["redirect"][r_parts[0]] = r_parts[1]
result["easymapping"] = easymapping.values()
cfg = HaproxyConfigGenerator(result)
print(cfg.generate())
# print(jsonStr)

8
templates/bind.j2 Normal file
View file

@ -0,0 +1,8 @@
{% if "ssl_cert" in o %}
bind *:{{ o["port"] }} ssl crt {{ o["ssl_cert"] }}
{% elif "h2" in o and o["h2"] %}
bind *:{{ o["port"] }} proto h2
option http-use-htx
{% else %}
bind *:{{ o["port"] }}
{% endif %}

View file

@ -0,0 +1,11 @@
mode http
{% for k in o["redirect"] %}
redirect prefix {{ o["redirect"][k] }} code 301 if { hdr(host) -i {{ k }} }
{% endfor %}
{% for k in o["hosts"] %}
{% set host = k.replace(".", "_") + "_{0}_{1}".format(o["port"], salt) %}
acl is_rule_{{ host }}_1 hdr(host) -i {{ k }}
acl is_rule_{{ host }}_2 hdr(host) -i {{ k }}:{{ o["port"] }}
use_backend srv_{{ host }} if is_rule_{{ host }}_1 OR is_rule_{{ host }}_2
{% endfor %}

View file

@ -0,0 +1,6 @@
mode tcp
option tcplog
log global
{% set backend = (o["hosts"]|first) %}
default_backend srv_{{ backend.replace(".", "_") + "_{0}_{1}".format(o["port"], salt) }}

View file

@ -1,3 +1,8 @@
global
log stdout format raw local0 info
maxconn 2000
tune.ssl.default-dh-param 2048
defaults
log global
@ -14,11 +19,6 @@ defaults
errorfile 504 /etc/haproxy/errors-custom/504.http
{% endif %}
global
log /dev/log local0
maxconn 2000
tune.ssl.default-dh-param 2048
{% if "stats" in data %}
frontend stats
bind *:{{ data["stats"]["port"] | default(1936) }}
@ -37,32 +37,31 @@ backend srv_stats
mode http
server Local 127.0.0.1:{{ data["stats"]["port"] | default(1936) }}
{% endif %}
{% for o in data["easymapping"] %}
{% for o in data["easymapping"] -%}
{% set mode = o["mode"] or "http" %}
{% set salt = loop.index %}
frontend http_in_{{ o["port"] }}_{{ salt }}
bind *:{{ o["port"] }} {{ " ssl crt " + o["ssl_cert"] if "ssl_cert" in o else "" }}
mode http
{% for k in o["redirect"] -%}
redirect prefix {{ o["redirect"][k] }} code 301 if { hdr(host) -i {{ k }} }
{% endfor -%}
frontend {{ mode }}_in_{{ o["port"] }}_{{ salt }}
{% include "bind.j2" %}
{% if mode == "http" %}
{% include "frontend-mode-http.j2" %}
{% else %}
{% include "frontend-mode-tcp.j2" %}
{% endif %}
{% for k in o["hosts"] %}
{% set host = k.replace(".", "_") + "_{0}_{1}".format(o["port"], salt) %}
acl is_rule_{{ host }}_1 hdr(host) -i {{ k }}
acl is_rule_{{ host }}_2 hdr(host) -i {{ k }}:{{ o["port"] }}
use_backend srv_{{ host }} if is_rule_{{ host }}_1 OR is_rule_{{ host }}_2
{% endfor %}
{% for k in o["hosts"] %}
{% for k in o["hosts"] -%}
{% set host = k.replace(".", "_") + "_{0}_{1}".format(o["port"], salt) %}
backend srv_{{ host }}
balance roundrobin
mode http
mode {{ mode }}
{% if 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 {{ o["hosts"][k] }} check weight 1
{% elif mode == "tcp" %}
option tcp-check
tcp-check connect{{ " ssl" if o["health-check"] == "ssl" }}
{% endif %}
server srv {{ o["hosts"][k] }} check weight 1{{ " verify none" if o["health-check"] == "ssl" }}
{% endfor %}
{% endfor %}

0
tests/__init__.py Normal file
View file

5
tests/context.py Normal file
View file

@ -0,0 +1,5 @@
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import easymapping

5
tests/fixtures/no-services vendored Normal file
View file

@ -0,0 +1,5 @@
swarm-prom_caddy={"com.docker.stack.image":"stefanprodan/caddy","com.docker.stack.namespace":"swarm-prom"}
swarm-prom_cadvisor={"com.docker.stack.image":"google/cadvisor","com.docker.stack.namespace":"swarm-prom"}
swarm-prom_dockerd-exporter={"com.docker.stack.image":"stefanprodan/caddy","com.docker.stack.namespace":"swarm-prom"}
swarm-prom_unsee={"com.docker.stack.image":"cloudflare/unsee:v0.8.0","com.docker.stack.namespace":"swarm-prom"}
test_proxy={"com.docker.stack.image":"byjg/easy-haproxy","com.docker.stack.namespace":"test"}

5
tests/fixtures/services vendored Normal file
View file

@ -0,0 +1,5 @@
portainer-agent_agent={"com.docker.stack.image":"portainer/agent:1.5.1","com.docker.stack.namespace":"portainer-agent"}
my-stack_agent={"com.byjg.easyhaproxy.definitions":"agent","com.byjg.easyhaproxy.host.agent":"agent.quantum.example.org","com.byjg.easyhaproxy.localport.agent":"9001","com.byjg.easyhaproxy.mode.agent":"tcp","com.byjg.easyhaproxy.port.agent":"31339","com.docker.stack.image":"portainer/agent:1.5.1","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_reverse-proxy={"com.docker.stack.image":"quay.io/pngmbh/easy-haproxy:tcp-mode","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}

2
tests/fixtures/services-tcp vendored Normal file
View file

@ -0,0 +1,2 @@
test_agent={"com.byjg.easyhaproxy.definitions":"agent","com.byjg.easyhaproxy.host.agent":"agent.quantum.local","com.byjg.easyhaproxy.localport.agent":"9001","com.byjg.easyhaproxy.mode.agent":"tcp","com.byjg.easyhaproxy.port.agent":"31339","com.docker.stack.image":"portainer/agent:1.5.1","com.docker.stack.namespace":"test", "com.byjg.easyhaproxy.health-check.agent":"ssl"}
test_proxy={"com.docker.stack.image":"byjg/easy-haproxy:local","com.docker.stack.namespace":"test"}

23
tests/fixtures/static.yml vendored Normal file
View file

@ -0,0 +1,23 @@
stats:
username: admin
password: test123
port: 1936 # Optional (default 1936)
customerrors: true # Optional (default false)
easymapping:
- port: 80
hosts:
host1.com.br: container:5000
host2.com.br: other:3000
redirect:
www.host1.com.br: http://host1.com.br
- port: 443
ssl_cert: BASE64_PEM_CERTIFICATE
hosts:
host1.com.br: container:80
- port: 8080
hosts:
host3.com.br: domain:8181

32
tests/test_labels.py Normal file
View file

@ -0,0 +1,32 @@
from .context import easymapping
import json
import pytest
def test_label_generation():
label = easymapping.DockerLabelHandler("foo")
assert label.create("bar") == "foo.bar"
assert label.create(["bar", "foobar"]) == "foo.bar.foobar"
def test_label_data():
label = easymapping.DockerLabelHandler("base")
label.set_data(json.loads('{"base.definitions":"h2"}'))
label_name = label.create("definitions")
assert label_name == "base.definitions"
assert label.has_label(label_name)
assert label.get(label_name) == "h2"
def test_label_complex_key():
label = easymapping.DockerLabelHandler("till")
data = dict()
data["till.definitions"] = "h2"
data["till.host.h2"] = "fqdn.example.org"
data["till.mode.h2"] = "tcp"
label.set_data(json.loads(json.dumps(data)))
assert label.get(label.create(["host", "h2"])) == "fqdn.example.org"
assert label.get(label.create(["mode", "h2"])) == "tcp"

108
tests/test_parser.py Normal file
View file

@ -0,0 +1,108 @@
from .context import easymapping
import pytest
import os
import yaml
def load_fixture(file):
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/fixtures/" + file, 'r') as content_file:
lineList = content_file.readlines()
return lineList
def test_parser_doesnt_crash():
lineList = load_fixture("no-services")
result = {
"customerrors": False
}
cfg = easymapping.HaproxyConfigGenerator(result)
haproxy_config = cfg.generate(lineList)
assert len(haproxy_config) > 0
assert "frontend" not in haproxy_config
assert "backend" not in haproxy_config
def test_parser_finds_services():
lineList = load_fixture("services")
result = {
"customerrors": False
}
cfg = easymapping.HaproxyConfigGenerator(result)
haproxy_config = cfg.generate(lineList)
assert len(haproxy_config) > 0
assert "mode tcp" in haproxy_config
assert "mode http" in haproxy_config
assert "frontend tcp_in_31339_1" in haproxy_config
assert "frontend http_in_31337_2" in haproxy_config
def test_parser_static():
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/fixtures/static.yml", 'r') as content_file:
parsed = yaml.load(content_file.read(), Loader=yaml.FullLoader)
cfg = easymapping.HaproxyConfigGenerator(parsed)
haproxy_config = cfg.generate()
assert len(haproxy_config) > 0
# assert on auth on stats
assert "stats auth admin:test123" in haproxy_config
# assert that we found redirect
assert "redirect prefix http://host1.com.br code 301 if { hdr(host) -i www.host1.com.br }" in haproxy_config
# assert that we found the services
frontend_http_cfg = "frontend http_in_80_1\n"
frontend_http_cfg += " bind *:80"
assert frontend_http_cfg in haproxy_config
frontend_https_cfg = "frontend http_in_443_2\n"
frontend_https_cfg += " bind *:443"
assert frontend_https_cfg in haproxy_config
# print(haproxy_config)
frontend_http8080_cfg = "frontend http_in_8080_3\n"
frontend_http8080_cfg += " bind *:8080"
assert frontend_http8080_cfg in haproxy_config
# verify ssl config with certificate
frontend_ssl_cfg = "frontend http_in_443_2\n"
frontend_ssl_cfg += " bind *:443 ssl crt BASE64_PEM_CERTIFICATE"
assert frontend_ssl_cfg in haproxy_config
def test_parser_tcp():
lineList = load_fixture("services-tcp")
result = {
"customerrors": False
}
cfg = easymapping.HaproxyConfigGenerator(result)
haproxy_config = cfg.generate(lineList)
# print(haproxy_config)
frontend_cfg = "frontend tcp_in_31339_1\n"
frontend_cfg += " bind *:31339\n"
frontend_cfg += " mode tcp\n"
frontend_cfg += " option tcplog\n"
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