1
0
Fork 0

Merge pull request #44 from byjg/issue/43

Issue #43 - Load Balance + Custom HAProxy config
This commit is contained in:
Joao M 2023-07-03 15:03:58 -05:00 committed by GitHub
commit ab0452388b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 503 additions and 150 deletions

View file

@ -19,6 +19,14 @@ EasyHAProxy can detect and configure HAProxy automatically on the following plat
- Docker Swarm
- Kubernetes
## Who is using?
EasyHAProxy is part of some projects:
- Dokku
- MicroK8s
See detailed instructions on how to install below.
## EasyHAProxy Mission
Easy to set up and low configuration to numerous features.
@ -38,7 +46,7 @@ EasyHAProxy will discover the services based on the Docker Tags of the container
Also, it is possible to set up HAProxy from a simple Yaml file instead of creating `haproxy.cfg` file.
## How Does It Works?
## How Does It Work?
You don't need to change your current infrastructure and don't need to learn the HAProxy configuration.

View file

@ -1,4 +1,4 @@
FROM alpine:3.16
FROM alpine:3.18
ARG RELEASE_VERSION_ARG
@ -11,7 +11,6 @@ COPY src/ /scripts/
COPY build/assets /
RUN apk add --no-cache haproxy bash python3 py3-pip py-yaml certbot openssl \
&& ln -s /usr/bin/python3 /usr/bin/python \
&& pip3 install --upgrade pip \
&& pip install -r requirements.txt \
&& pytest -s -vv tests/ \

View file

@ -11,10 +11,11 @@
| easyhaproxy.[definition].redirect | (Optional) JSON containing key/value pair from host/to URL redirect. | *empty* | {"foo.com":"https://bla.com", "bar.com":"https://bar.org"} |
| easyhaproxy.[definition].sslcert | (Optional) Cert PEM Base64 encoded. Do not use this if `certbot` is enabled. | *empty* | base64 cert + key |
| easyhaproxy.[definition].ssl | (Optional) If `true` you need to provide certificate as a file. See below. Do not use with `sslcert`. | false | true or false |
| easyhaproxy.[definition].health-check | (Optional) `ssl`, enable health check via SSL in `mode tcp` | *empty* | ssl |
| easyhaproxy.[definition].ssl-check | (Optional) `ssl`, enable health check via SSL in `mode tcp` | *empty* | ssl |
| easyhaproxy.[definition].certbot | (Optional) Generate certificate with certbot. Do not use with `sslcert` parameter. More info [here](acme.md). | false | true OR false |
| easyhaproxy.[definition].redirect_ssl | (Optional) Redirect all requests to https | false | true OR false |
| easyhaproxy.[definition].clone_to_ssl | (Optional) It copies the configuration to HTTPS(443) and disable SSL from the current config. **Do not use* this with `ssl` or `certbot` parameters | false | true OR false |
| easyhaproxy.[definition].balance | (Optional) HAProxy balance algorithm. See [HAProxy documentation](https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#4.2-balance) | roundrobin | roundrobin, source, uri, url_param, hdr, rdp-cookie, leastconn, first, static-rr, rdp-cookie, hdr_dom, map-based |
The `definition` is a string that will group all configurations togethers. Different `definition` will create different configurations.

View file

@ -20,6 +20,5 @@
| HAPROXY_CUSTOMERRORS | (Optional) If HAProxy will use custom HTML errors. true/false. | `false` |
----
[Open source ByJG](http://opensource.byjg.com)

View file

@ -4,8 +4,12 @@
This method will use a docker standalone installation to discover the containers and configure the HAProxy.
The only requirement is that containers and EasyHAProxy must be in the same docker network.
If not, EasyHAProxy will connect the container with the EasyHAProxy network.
You cannot mix docker containers with swarm containers.
The only request is that containers and EasyHAProxy must be in the same docker network.
If you don't add to your services the same network EasyHAProxy is connected to, EasyHAProxy will attach it network to your container.
Also, it is highly recommended you create a network external to EasyHAProxy.
e.g.:
@ -53,7 +57,6 @@ Please follow the [docker label configuration](container-labels.md) to see other
You can configure the behavior of the EasyHAProxy by setup specific environment variables. To get a list of the variables, please follow the [docker container environment](docker-environment.md)
## Setup certificates with ACME (e.g. Letsencrypt)
Follow [this link](acme.md)

View file

@ -71,7 +71,7 @@ Once the container is running, EasyHAProxy will detect automatically and start t
You don't need to expose any port in your container.
Caveats:
Notes:
- At this point, the implementation doesn't support all ingress properties or wildcard domains.
- The ingress will publish the ports 80 and 443, plus 1936 if stats are enabled.
@ -80,7 +80,7 @@ Caveats:
## Kubernetes annotations
| annotation | Description | Default | Example |
|-----------------------------|-------------------------------------------------------------------------------------|--------------|---------------------------|
|----------------------------------|-------------------------------------------------------------------------------------|--------------|---------------------------------------|
| kubernetes.io/ingress.class | (required) Activate EasyHAProxy. | **required** | easyhaproxy-ingress |
| easyhaproxy.redirect_ssl | (optional) Boolean. Force redirect all endpoints to HTTPS. | false | true or false |
| easyhaproxy.certbot | (optional) Boolean. It will request certbot certificates for the ingresses domains. | false | true or false |

View file

@ -20,6 +20,9 @@ customerrors: true # Optional (default false)
ssl_mode: default
logLevel:
haproxy: INFO
certbot: {
"email": "acme@example.org"
}
@ -83,6 +86,11 @@ customerrors: true # Optional (default false)
ssl_mode: default # Optional
logLevel:
certbot: DEBUG # Optional (default: DEBUG). Can be: TRACE,DEBUG,INFO,WARN,ERROR,FATAL
easyhaproxy: DEBUG # Optional (default: DEBUG). Can be: TRACE,DEBUG,INFO,WARN,ERROR,FATAL
haproxy: INFO # Optional (default: INFO). Can be: TRACE,DEBUG,INFO,WARN,ERROR,FATAL
certbot: { # Optional. If you enable `certbot` will need to setu0p this,
# otherwise the certificate will be issued
"email": "acme@example.org"

View file

@ -5,13 +5,17 @@
This method will use a docker swarm installation to discover the containers and configure the HAProxy.
The advantage of this method is that you can discover containers in other nodes from the cluster.
The only requirement is that containers and EasyHAProxy must be in the same docker swarm network.
If not, EasyHAProxy will connect the service with the EasyHAProxy service network.
You cannot mix docker containers with swarm containers.
The only request is that containers and EasyHAProxy must be in the same docker swarm network.
If you don't add to your services the same network EasyHAProxy is connected to, EasyHAProxy will attach it network to your container.
Also, it is highly recommended you create a network external to EasyHAProxy.
e.g.:
```bash
docker network create -d overlay easyhaproxy
docker network create -d overlay --attachable easyhaproxy
```
And then deploy the EasyHAProxy stack:
@ -79,8 +83,6 @@ networks:
external: true
```
Note: The services to be discovered **don't need** to be in the same network as EasyHAProxy is.
Once the container is running, EasyHAProxy will detect automatically and start to redirect all traffic from `example.org:80` to your container.
You don't need to expose any port in your container.

14
docs/volumes.md Normal file
View file

@ -0,0 +1,14 @@
# Volumes
You can map the following volumes:
| Volume | Description |
|-----------------------------|-------------------------------------------------------------------------------------------------------------------------------|
| /etc/haproxy/static/ | The folder that will contain the [config.yml](static.md) file for static configuration |
| /certs/haproxy/ | The folder that will contain the certificates (`PEM`) for the [SSL](ssl.md) |
| /certs/certbot/ | The folder that will contain the certificates (`PEM`) processed by Certbot (e.g. Let's Encrypt). More info: [acme](acme.md). |
| /etc/haproxy/conf.d/ | The folder that will contain the [custom configuration](other.md) files. |
| /etc/haproxy/errors-custom/ | The folder that will contain the [custom error](other.md) html files. |
----
[Open source ByJG](http://opensource.byjg.com)

View file

@ -0,0 +1,82 @@
-----BEGIN CERTIFICATE-----
MIIFDTCCAvWgAwIBAgIURi+w1ZVgeedTlNIAwqQBMJv6dXswDQYJKoZIhvcNAQEL
BQAwFjEUMBIGA1UEAwwLaG9zdDEubG9jYWwwHhcNMjEwODEwMTg0OTA2WhcNMzEw
ODA4MTg0OTA2WjAWMRQwEgYDVQQDDAtob3N0MS5sb2NhbDCCAiIwDQYJKoZIhvcN
AQEBBQADggIPADCCAgoCggIBAMBDAhLAygJuaW6w6ffigzTAAGXpmEz0tIxn1k4Z
x5wN5rpv/qu0QMYz+Av2u1eOKEKZeaFRVpT0r93dX7IvbEZHt25GPiBvlLGqhjKR
PnSk/7U8XmsnttUAV7rVEK1UrdFw8/IwriQC+dhr0mnYfSDMkvBoMFpdhVNTrbAZ
1TB6rQjE7Ar0Mt8my96XJmwrcjK2Tj+E2rgPIUz1e5cekFYIDSBatmw+3+vr+T5x
FNFkJ2o30W5o8ZflCJJzrVaihqQics6ZKDgpf7iqXMFiwWIlhdQpGvx5Gf/KFTK9
UaOnRZz/X+2CebAFaTHR3k/PYppWTgBBBuRvlpCw+wdnkmteC0SQRF91QWVr7ejo
7KaOlGI5VtvMUsWvTeAZmpaymIaATETuOJaY0JU11OmLeD9DOj5E2SQ7qIX/pFcp
xpzG5j4c+MlgvxP2VAkNTeAXCaYiPBQH5ZZg0HE2WnB1KhLRFlHd4iHQD2GJ5yN/
6fCFBfZfKSeK8JauwxgWkra53OcDq/mKd+DA/dK+/ruG7tqwVgIa04HOplzM7LYR
GB0Irs9+lr5/PJbQZmU073Mdn6cXAg3p+6wvwFlDkS5v13gBDYNHtF62bc551edF
Z6kGzJ7wmGRo84aBP7MuRZeReLOrSS67a1wLdzZsMnP1TJ7x9Lfr9MKl2uDnQdnY
ex8DAgMBAAGjUzBRMB0GA1UdDgQWBBSQ/mtZd6h8en9YQVH6HO1PlWWiqzAfBgNV
HSMEGDAWgBSQ/mtZd6h8en9YQVH6HO1PlWWiqzAPBgNVHRMBAf8EBTADAQH/MA0G
CSqGSIb3DQEBCwUAA4ICAQChQYNuah3+mTpIBDYxGrjTJNuOTIMaWzMyi1tkf+L0
sEGwpbmAO2mWWQYF7WVLsi98PULh3adjt2jiud9VlaaC6gnwn5Zo1+Pilo9sNLLW
6ij0+rN4kwIm/pNqi+jDuu2cvAuHIwZWeh8bEe/5UCxo4ihmWFQN8eJ6TUKCphRC
6Eor/SSZZBQHgPl0BchzHOkwu7R3LCndRqxjhAoVb9yQOV+ZsmTeJXulwNzJ1uLt
T8OIgIiDpmBo7HSN2H0k3chx00AsjUyJ9mmAWPejFe/KXLRPcVZR17jhzgfIBEzs
M5WtWFm1aHDjVv6M6iteVm61E9T+k/M11ru1e2YwsxTDvb6x04mcrNu9soqddBbr
VfpluuoQ/hEAbXtFNPoTySpz0cwOwcHCowVOLmdKgvImszZiMyHHG8VGGmPh88n7
wVxb0gV0P4RMrcMLdeTdn55YQr1CqBr34eB6ol6AsbTm3VzBHRVmFNksl1o5JB5t
tXLgF/G8/rzJ/4m1PaVuxrB7DxUmIk8EPbSIVkvZvd7LBzKwQ6IfVaucewHfEajQ
VIiexSMiFc7lw3KnxjOHZjf6FM9VYg3No++GdC99s7LkIuJwAMLNqTQ7Hvhn7YvP
4FlSIgc6xj0YkGZEQlb5o/5nauEqQU0ABgw6jtI4NxrNLT6cp7CO4M0xIDEg/3YD
aA==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
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
YkU14WzQKleFkiBJI9lVvnfgGnOlgg0=
-----END PRIVATE KEY-----

View file

@ -0,0 +1,40 @@
# To Install
# docker network create --driver overlay --attachable easyhaproxy
# docker stack deploy -c easyhaproxy.yml easyhaproxy
version: "3"
services:
haproxy:
image: byjg/easy-haproxy:4.3.1-rc2
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./certs:/certs/haproxy
- certs_certbot:/certs/certbot
deploy:
replicas: 1
environment:
EASYHAPROXY_DISCOVER: swarm
EASYHAPROXY_SSL_MODE: "loose"
EASYHAPROXY_LETSENCRYPT_EMAIL: changeme@example.org
HAPROXY_CUSTOMERRORS: "true"
HAPROXY_USERNAME: admin
HAPROXY_PASSWORD: password
HAPROXY_STATS_PORT: 1936
ports:
- "80:80/tcp"
- "443:443/tcp"
- "1936:1936/tcp"
networks:
- easyhaproxy
networks:
easyhaproxy:
external: true
volumes:
certs_certbot:
# external: true
# certs_haproxy:
# external: true

View file

@ -0,0 +1,28 @@
# To install:
# docker stack deploy -c portainer.yml portainer
version: "3"
services:
portainer:
image: portainer/portainer-ce:latest
volumes:
- portainer_data:/data portainer
- /var/run/docker.sock:/var/run/docker.sock
deploy:
replicas: 1
labels:
# easyhaproxy.http.redirect_ssl: true
# easyhaproxy.http.certbot: true
easyhaproxy.http.host: portainer.local
easyhaproxy.http.port: 80
easyhaproxy.http.localport: 9000
volumes:
certs_certbot:
external: true
# certs_haproxy:
# external: true
portainer_data:
# external: true

View file

@ -1,3 +1,6 @@
# To install:
# docker stack deploy -c services.yml services
#
# To test:
# curl -k -H "Host: host1.local" https://127.0.0.1/
# curl -k -H "Host: host2.local" https://127.0.0.1/
@ -18,25 +21,6 @@
version: "3"
services:
haproxy:
image: byjg/easy-haproxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./host2.local.pem:/certs/haproxy/host2.local.pem
deploy:
replicas: 1
environment:
EASYHAPROXY_DISCOVER: swarm
EASYHAPROXY_SSL_MODE: "loose"
HAPROXY_CUSTOMERRORS: "true"
HAPROXY_USERNAME: admin
HAPROXY_PASSWORD: password
HAPROXY_STATS_PORT: 1936
ports:
- "80:80/tcp"
- "443:443/tcp"
- "1936:1936/tcp"
container:
image: byjg/static-httpserver
deploy:

View file

@ -114,7 +114,7 @@ class HaproxyConfigGenerator:
if port not in easymapping:
easymapping[port] = {
"mode": mode,
"health-check": "",
"ssl-check": "",
"port": port,
"hosts": dict(),
"redirect": dict(),
@ -126,8 +126,8 @@ class HaproxyConfigGenerator:
"80"
)
easymapping[port]["health-check"] = self.label.get(
self.label.create([definition, "health-check"]),
easymapping[port]["ssl-check"] = self.label.get(
self.label.create([definition, "ssl-check"]),
""
)
@ -142,6 +142,10 @@ class HaproxyConfigGenerator:
easymapping[port]["hosts"][hostname]["redirect_ssl"] = self.label.get_bool(
self.label.create([definition, "redirect_ssl"])
)
easymapping[port]["hosts"][hostname]["balance"] = self.label.get(
self.label.create([definition, "balance"]),
"roundrobin"
)
easymapping[port]["redirect"] = self.label.get_json(
self.label.create([definition, "redirect"])
@ -151,7 +155,7 @@ class HaproxyConfigGenerator:
if "443" not in easymapping:
easymapping["443"] = {
"mode": "http",
"health-check": "ssl",
"ssl-check": "ssl",
"port": "443",
"hosts": dict(),
"redirect": dict(),

View file

@ -27,6 +27,13 @@ class ContainerEnv:
env_vars["lookup_label"] = os.getenv("EASYHAPROXY_LABEL_PREFIX") if os.getenv(
"EASYHAPROXY_LABEL_PREFIX") else "easyhaproxy"
env_vars["logLevel"] = {
"easyhaproxy": os.getenv("EASYHAPROXY_LOG_LEVEL") if os.getenv(
"EASYHAPROXY_LOG_LEVEL") else Functions.DEBUG,
"haproxy": os.getenv("HAPROXY_LOG_LEVEL") if os.getenv("HAPROXY_LOG_LEVEL") else Functions.INFO,
"certbot": os.getenv("CERTBOT_LOG_LEVEL") if os.getenv("CERTBOT_LOG_LEVEL") else Functions.DEBUG,
}
env_vars["certbot"] = {
"autoconfig": os.getenv("EASYHAPROXY_CERTBOT_AUTOCONFIG", ""),
"email": os.getenv("EASYHAPROXY_CERTBOT_EMAIL", ""),
@ -72,7 +79,7 @@ class ContainerEnv:
env_vars["certbot"]["eab_kid"] = os.environ['EASYHAPROXY_CERTBOT_EAB_KID'] = resp["eab_kid"]
env_vars["certbot"]["eab_hmac_key"] = os.environ['EASYHAPROXY_CERTBOT_EAB_HMAC_KEY'] = resp["eab_hmac_key"]
else:
os.environ["EASYHAPROXY_CERTBOT_EMAIL"] = ""
del os.environ["EASYHAPROXY_CERTBOT_EMAIL"]
Functions.log(Functions.CERTBOT_LOG, Functions.ERROR, "Could not obtain ZeroSSL credentials " + resp["error"]["type"])
os.environ['EASYHAPROXY_CERTBOT_SERVER'] = env_vars["certbot"]["server"]
@ -174,26 +181,20 @@ class Functions:
class Consts:
easyhaproxy_config = "/etc/haproxy/static/config.yml"
haproxy_config = "/etc/haproxy/haproxy.cfg"
custom_config_folder = "/etc/haproxy/conf.d"
certs_certbot = "/certs/certbot"
certs_haproxy = "/certs/haproxy"
class DaemonizeHAProxy:
def __init__(self):
def __init__(self, custom_config_folder = None):
self.process = None
self.thread = None
self.sleep_secs = None
self.custom_config_folder = custom_config_folder if custom_config_folder is not None else Consts.custom_config_folder
def haproxy(self, action):
if action == "start":
self.__prepare(
"/usr/sbin/haproxy -W -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /var/run/haproxy.sock")
else:
return_code, pid_tmp = Functions().run_bash(Functions.HAPROXY_LOG, "cat /run/haproxy.pid", log_output=False)
pid = "".join(pid_tmp)
self.__prepare(
"/usr/sbin/haproxy -W -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -x /var/run/haproxy.sock -sf %s" %
pid)
self.__prepare(self.get_haproxy_command(action))
if self.process is None:
return
@ -201,6 +202,18 @@ class DaemonizeHAProxy:
self.thread = Process(target=self.__start, args=())
self.thread.start()
def get_haproxy_command(self, action, pid_file="/run/haproxy.pid"):
custom_config_files = ""
if len(list(self.get_custom_config_files().keys())) != 0:
custom_config_files = "-f %s" % (self.custom_config_folder)
if action == "start":
return "/usr/sbin/haproxy -W -f /etc/haproxy/haproxy.cfg %s -p %s -S /var/run/haproxy.sock" % (custom_config_files, pid_file)
else:
return_code, output = Functions().run_bash(Functions.HAPROXY_LOG, "cat %s" % pid_file, log_output=False)
pid = "".join(output)
return "/usr/sbin/haproxy -W -f /etc/haproxy/haproxy.cfg %s -p %s -x /var/run/haproxy.sock -sf %s" % (custom_config_files, pid_file, pid)
def __prepare(self, command):
source = Functions.HAPROXY_LOG
if not isinstance(command, (list, tuple)):
@ -250,6 +263,16 @@ class DaemonizeHAProxy:
time.sleep(self.sleep_secs)
def get_custom_config_files(self):
if not os.path.exists(self.custom_config_folder):
return {}
files = {}
for file in os.listdir(self.custom_config_folder):
if file.endswith(".cfg"):
files[os.path.join(self.custom_config_folder, file)] = os.path.getmtime(os.path.join(self.custom_config_folder, file))
return dict(sorted(files.items(), key=lambda t: t[0]))
class Certbot:
def __init__(self, certs):

View file

@ -23,6 +23,7 @@ def start():
old_haproxy = None
haproxy = DaemonizeHAProxy()
current_custom_config_files = haproxy.get_custom_config_files()
haproxy.haproxy("start")
haproxy.sleep()
@ -35,8 +36,7 @@ def start():
try:
old_parsed = processor_obj.get_parsed_object()
processor_obj.refresh()
if certbot.check_certificates(certbot_certs_found) or DeepDiff(old_parsed,
processor_obj.get_parsed_object()) != {} or not haproxy.is_alive():
if certbot.check_certificates(certbot_certs_found) or DeepDiff(old_parsed, processor_obj.get_parsed_object()) != {} or not haproxy.is_alive() or DeepDiff(current_custom_config_files, haproxy.get_custom_config_files()) != {}:
Functions.log(Functions.EASYHAPROXY_LOG, Functions.DEBUG, 'New configuration found. Reloading...')
Functions.log(Functions.EASYHAPROXY_LOG, Functions.TRACE,
'Object Found: %s' % (processor_obj.get_parsed_object()))
@ -47,6 +47,7 @@ def start():
'Found hosts: %s' % ", ".join(processor_obj.get_hosts())) # Needs to after save_config
old_haproxy = haproxy
haproxy = DaemonizeHAProxy()
current_custom_config_files = haproxy.get_custom_config_files()
haproxy.haproxy("reload")
old_haproxy.terminate()

View file

@ -22,6 +22,7 @@ class ProcessorInterface:
self.certbot_hosts = None
self.hosts = None
self.filename = filename
self.label = ContainerEnv.read()['lookup_label']
self.refresh()
@staticmethod
@ -151,24 +152,34 @@ class Swarm(ProcessorInterface):
def inspect_network(self):
ha_proxy_service_name = self.client.containers.get(socket.gethostname()).name.split('.')[0]
ha_proxy_network_id = None
swarm_ingress_id = None
# Get the HAProxy network and the ingress network
for endpoint in self.client.services.get(ha_proxy_service_name).attrs['Endpoint']["VirtualIPs"]:
network_name = self.client.networks.get(endpoint["NetworkID"]).name
if swarm_ingress_id is None and network_name == 'ingress':
swarm_ingress_id = endpoint["NetworkID"]
if ha_proxy_network_id is None and network_name != 'ingress':
ha_proxy_network_id = endpoint["NetworkID"]
if self.client.networks.get(ha_proxy_network_id).name != 'ingress':
if ha_proxy_network_id is not None and swarm_ingress_id is not None:
break
if ha_proxy_network_id is None:
raise "Could not find ingress network"
# Check if the service is attached to the HAProxy network
self.parsed_object = {}
for service in self.client.services.list():
if not any(self.label in key for key in service.attrs["Spec"]["Labels"]):
continue
ip_address = None
network_list = []
for endpoint in service.attrs["Endpoint"]["VirtualIPs"]:
if ha_proxy_network_id == endpoint["NetworkID"]:
ip_address = endpoint["Addr"].split("/")[0]
break
elif swarm_ingress_id != endpoint["NetworkID"]:
network_list.append(endpoint["NetworkID"])
# Attach the service to the HAProxy network
if ip_address is None:
network_list.append(ha_proxy_network_id)
service.update(networks = network_list)
@ -187,10 +198,9 @@ class Kubernetes(ProcessorInterface):
self.cert_cache = {}
super().__init__()
@staticmethod
def _check_annotation(annotations, key):
def _check_annotation(self, annotations, key, default=None):
if key not in annotations:
return None
return default
return annotations[key]
def inspect_network(self):
@ -210,9 +220,7 @@ class Kubernetes(ProcessorInterface):
redirect_ssl = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.redirect_ssl")
redirect = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.redirect")
mode = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.mode")
listen_port = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.listen_port")
if listen_port is None:
listen_port = 80
listen_port = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.listen_port", 80)
data = {"creation_timestamp": ingress.metadata.creation_timestamp.strftime("%x %X"),
"resource_version": ingress.metadata.resource_version, "namespace": ingress.metadata.namespace}
@ -259,6 +267,7 @@ class Kubernetes(ProcessorInterface):
rule_data["%s.redirect" % definition] = redirect
if mode is not None:
rule_data["%s.mode" % definition] = mode
rule_data["%s.balance" % definition] = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.balance", "roundrobin")
service_name = rule.http.paths[0].backend.service.name
try:

View file

@ -1,5 +1,5 @@
{% if "ssl" in o %}
bind *:{{ o["port"] }} ssl crt /certs/certbot/ alpn http/1.1 crt /certs/haproxy/ alpn http/1.1
bind *:{{ o["port"] }} ssl crt /certs/certbot/ alpn h2,http/1.1 crt /certs/haproxy/ alpn h2,http/1.1
{% elif "h2" in o and o["h2"] %}
bind *:{{ o["port"] }} proto h2
option http-use-htx

View file

@ -1,5 +1,18 @@
{% set log_definition = data["logLevel"] | default({}) %}
{% set log_level = log_definition["haproxy"] | default("INFO") | upper %}
{% if log_level == "TRACE" or log_level == "DEBUG" %}
{% set haproxy_log_level = "debug" %}
{% elif log_level == "INFO" %}
{% set haproxy_log_level = "info" %}
{% elif log_level == "WARN" %}
{% set haproxy_log_level = "warning" %}
{% elif log_level == "ERROR" %}
{% set haproxy_log_level = "err" %}
{% elif log_level == "FATAL" %}
{% set haproxy_log_level = "crit" %}
{% endif %}
global
log stdout format raw local0 info
log stdout format raw local0 {{ haproxy_log_level }}
maxconn 2000
{% if data["ssl_mode"] == "strict" %}
{% include "ssl_strict.j2" %}
@ -59,7 +72,7 @@ frontend {{ mode }}_in_{{ o["port"] }}
{% for k in o["hosts"] -%}
{% set host = k.replace(".", "_") + "_{0}".format(o["port"]) %}
backend srv_{{ host }}
balance roundrobin
balance {{ o["balance"] | default("roundrobin") }}
mode {{ mode }}
{% if mode == "http" %}
option forwardfor
@ -67,10 +80,10 @@ backend srv_{{ host }}
http-request add-header X-Forwarded-Proto https if { ssl_fc }
{% elif mode == "tcp" %}
option tcp-check
tcp-check connect{{ " ssl" if o["health-check"] == "ssl" }}
tcp-check connect{{ " ssl" if o["ssl-check"] == "ssl" }}
{% endif %}
{% for c in o["hosts"][k]["containers"] %}
server srv-{{ loop.index0 }} {{ c }} check weight 1{{ " verify none" if o["health-check"] == "ssl" }}
server srv-{{ loop.index0 }} {{ c }} check weight 1{{ " verify none" if o["ssl-check"] == "ssl" }}
{% endfor %}
{% endfor %}
{% endfor %}

View file

@ -36,7 +36,7 @@ backend srv_stats
server Local 127.0.0.1:1936
frontend http_in_443
bind *:443 ssl crt /certs/certbot/ alpn http/1.1 crt /certs/haproxy/ alpn http/1.1
bind *:443 ssl crt /certs/certbot/ alpn h2,http/1.1 crt /certs/haproxy/ alpn h2,http/1.1
mode http
acl is_rule_hostssl_local_443_1 hdr(host) -i hostssl.local

View file

@ -74,7 +74,7 @@ backend srv_test2_example_org_80
server srv-0 83d57d592e26:8080 check weight 1
frontend http_in_443
bind *:443 ssl crt /certs/certbot/ alpn http/1.1 crt /certs/haproxy/ alpn http/1.1
bind *:443 ssl crt /certs/certbot/ alpn h2,http/1.1 crt /certs/haproxy/ alpn h2,http/1.1
mode http
acl is_rule_test_example_org_443_1 hdr(host) -i test.example.org

View file

@ -49,7 +49,7 @@ backend srv_host1_local_80
server srv-0 5b69bc7fea1b:80 check weight 1
frontend http_in_443
bind *:443 ssl crt /certs/certbot/ alpn http/1.1 crt /certs/haproxy/ alpn http/1.1
bind *:443 ssl crt /certs/certbot/ alpn h2,http/1.1 crt /certs/haproxy/ alpn h2,http/1.1
mode http
acl is_rule_host2_local_443_1 hdr(host) -i host2.local

View file

@ -67,7 +67,7 @@ backend srv_node-exporter_quantum_example_org_31337
server srv-0 my-stack_node-exporter:9100 check weight 1
frontend http_in_443
bind *:443 ssl crt /certs/certbot/ alpn http/1.1 crt /certs/haproxy/ alpn http/1.1
bind *:443 ssl crt /certs/certbot/ alpn h2,http/1.1 crt /certs/haproxy/ alpn h2,http/1.1
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 }

View file

@ -74,7 +74,7 @@ backend srv_host2_com_br_80
server srv-0 other:3000 check weight 1
frontend http_in_443
bind *:443 ssl crt /certs/certbot/ alpn http/1.1 crt /certs/haproxy/ alpn http/1.1
bind *:443 ssl crt /certs/certbot/ alpn h2,http/1.1 crt /certs/haproxy/ alpn h2,http/1.1
mode http
acl is_rule_host1_com_br_443_1 hdr(host) -i host1.com.br

2
src/tests/fixtures/00_haproxy.cfg vendored Normal file
View file

@ -0,0 +1,2 @@
global
maxconn 4000

2
src/tests/fixtures/10_haproxy.cfg vendored Normal file
View file

@ -0,0 +1,2 @@
global
maxconn 5000

View file

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

View file

@ -1,6 +1,6 @@
import os
from functions import ContainerEnv
from functions import Functions, ContainerEnv
def test_container_env_empty():
@ -8,6 +8,11 @@ def test_container_env_empty():
"customerrors": False,
"ssl_mode": "default",
"lookup_label": "easyhaproxy",
"logLevel": {
"easyhaproxy": Functions.DEBUG,
"haproxy": Functions.INFO,
"certbot": Functions.DEBUG,
},
"certbot": {"autoconfig": "",
"eab_hmac_key": "",
"eab_kid": "",
@ -26,6 +31,11 @@ def test_container_env_customerrors():
"customerrors": True,
"ssl_mode": "default",
"lookup_label": "easyhaproxy",
"logLevel": {
"easyhaproxy": Functions.DEBUG,
"haproxy": Functions.INFO,
"certbot": Functions.DEBUG,
},
"certbot": {"autoconfig": "",
"eab_hmac_key": "",
"eab_kid": "",
@ -34,7 +44,7 @@ def test_container_env_customerrors():
"retry_count": 60}
} == ContainerEnv.read()
finally:
os.environ['HAPROXY_CUSTOMERRORS'] = ''
del os.environ['HAPROXY_CUSTOMERRORS']
def test_container_env_sslmode():
@ -44,6 +54,11 @@ def test_container_env_sslmode():
"customerrors": False,
"ssl_mode": "strict",
"lookup_label": "easyhaproxy",
"logLevel": {
"easyhaproxy": Functions.DEBUG,
"haproxy": Functions.INFO,
"certbot": Functions.DEBUG,
},
"certbot": {"autoconfig": "",
"eab_hmac_key": "",
"eab_kid": "",
@ -52,7 +67,7 @@ def test_container_env_sslmode():
"retry_count": 60}
} == ContainerEnv.read()
finally:
os.environ['EASYHAPROXY_SSL_MODE'] = ''
del os.environ['EASYHAPROXY_SSL_MODE']
def test_container_env_stats():
@ -63,6 +78,11 @@ def test_container_env_stats():
"customerrors": False,
"ssl_mode": "default",
"lookup_label": "easyhaproxy",
"logLevel": {
"easyhaproxy": Functions.DEBUG,
"haproxy": Functions.INFO,
"certbot": Functions.DEBUG,
},
"certbot": {"autoconfig": "",
"eab_hmac_key": "",
"eab_kid": "",
@ -71,8 +91,8 @@ def test_container_env_stats():
"retry_count": 60}
} == ContainerEnv.read()
finally:
os.environ['HAPROXY_USERNAME'] = ''
os.environ['HAPROXY_STATS_PORT'] = ''
del os.environ['HAPROXY_USERNAME']
del os.environ['HAPROXY_STATS_PORT']
def test_container_env_stats_password():
@ -88,6 +108,11 @@ def test_container_env_stats_password():
"port": "1936"
},
"logLevel": {
"easyhaproxy": Functions.DEBUG,
"haproxy": Functions.INFO,
"certbot": Functions.DEBUG,
},
"certbot": {"autoconfig": "",
"eab_hmac_key": "",
"eab_kid": "",
@ -96,7 +121,7 @@ def test_container_env_stats_password():
"retry_count": 60}
} == ContainerEnv.read()
finally:
os.environ['HAPROXY_PASSWORD'] = ''
del os.environ['HAPROXY_PASSWORD']
def test_container_env_stats_password_2():
@ -113,6 +138,11 @@ def test_container_env_stats_password_2():
"password": "xyz",
"port": "2101"
},
"logLevel": {
"easyhaproxy": Functions.DEBUG,
"haproxy": Functions.INFO,
"certbot": Functions.DEBUG,
},
"certbot": {"autoconfig": "",
"eab_hmac_key": "",
"eab_kid": "",
@ -121,9 +151,9 @@ def test_container_env_stats_password_2():
"retry_count": 60}
} == ContainerEnv.read()
finally:
os.environ['HAPROXY_USERNAME'] = ''
os.environ['HAPROXY_STATS_PORT'] = ''
os.environ['HAPROXY_PASSWORD'] = ''
del os.environ['HAPROXY_USERNAME']
del os.environ['HAPROXY_STATS_PORT']
del os.environ['HAPROXY_PASSWORD']
def test_container_env_certbot_email():
@ -133,6 +163,11 @@ def test_container_env_certbot_email():
"customerrors": False,
"ssl_mode": "default",
"lookup_label": "easyhaproxy",
"logLevel": {
"easyhaproxy": Functions.DEBUG,
"haproxy": Functions.INFO,
"certbot": Functions.DEBUG,
},
"certbot": {
"autoconfig": "",
'eab_hmac_key': "",
@ -143,7 +178,7 @@ def test_container_env_certbot_email():
}
} == ContainerEnv.read()
finally:
os.environ['EASYHAPROXY_CERTBOT_EMAIL'] = ''
del os.environ['EASYHAPROXY_CERTBOT_EMAIL']
def test_container_env_certbot_full():
@ -157,6 +192,11 @@ def test_container_env_certbot_full():
"customerrors": False,
"ssl_mode": "default",
"lookup_label": "easyhaproxy",
"logLevel": {
"easyhaproxy": Functions.DEBUG,
"haproxy": Functions.INFO,
"certbot": Functions.DEBUG,
},
"certbot": {
"autoconfig": "",
"email": "acme@example.org",
@ -167,4 +207,37 @@ def test_container_env_certbot_full():
}
} == ContainerEnv.read()
finally:
os.environ['EASYHAPROXY_CERTBOT_EMAIL'] = ''
del os.environ['EASYHAPROXY_CERTBOT_EMAIL']
del os.environ['EASYHAPROXY_CERTBOT_SERVER']
del os.environ['EASYHAPROXY_CERTBOT_EAB_KID']
del os.environ['EASYHAPROXY_CERTBOT_EAB_HMAC_KEY']
del os.environ['EASYHAPROXY_CERTBOT_RETRY_COUNT']
def test_container_log_level():
os.environ['CERTBOT_LOG_LEVEL'] = Functions.TRACE
os.environ['EASYHAPROXY_LOG_LEVEL'] = Functions.ERROR
os.environ['HAPROXY_LOG_LEVEL'] = Functions.FATAL
try:
assert {
"customerrors": False,
"ssl_mode": "default",
"lookup_label": "easyhaproxy",
"logLevel": {
"easyhaproxy": Functions.ERROR,
"haproxy": Functions.FATAL,
"certbot": Functions.TRACE,
},
"certbot": {
"autoconfig": "",
'eab_hmac_key': "",
'eab_kid': "",
"email": "",
"server": False,
"retry_count": 60
}
} == ContainerEnv.read()
finally:
del os.environ['CERTBOT_LOG_LEVEL']
del os.environ['EASYHAPROXY_LOG_LEVEL']
del os.environ['HAPROXY_LOG_LEVEL']

View file

@ -0,0 +1,48 @@
import os
from functions import DaemonizeHAProxy, Functions
def test_daemonize_haproxy():
daemon = DaemonizeHAProxy()
assert daemon is not None
def test_daemonize_haproxy_check_config():
daemon = DaemonizeHAProxy()
filed = daemon.get_custom_config_files()
assert filed == {}
def test_daemonize_haproxy_get_haproxy_command_start():
daemon = DaemonizeHAProxy()
command = daemon.get_haproxy_command("start")
assert command == "/usr/sbin/haproxy -W -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /var/run/haproxy.sock"
def test_daemonize_haproxy_get_haproxy_command_reload():
daemon = DaemonizeHAProxy()
command = daemon.get_haproxy_command("reload")
assert command == "/usr/sbin/haproxy -W -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -x /var/run/haproxy.sock -sf "
def test_daemonize_haproxy_check_config():
daemon = DaemonizeHAProxy(os.path.abspath(os.path.dirname(__file__)) + '/fixtures')
filed = daemon.get_custom_config_files()
assert filed == {
os.path.dirname(__file__) + "/fixtures/00_haproxy.cfg": os.path.getmtime(os.path.dirname(__file__) + "/fixtures/00_haproxy.cfg"),
os.path.dirname(__file__) + "/fixtures/10_haproxy.cfg": os.path.getmtime(os.path.dirname(__file__) + "/fixtures/10_haproxy.cfg")
}
def test_daemonize_haproxy_get_haproxy_command_start():
daemon = DaemonizeHAProxy(os.path.abspath(os.path.dirname(__file__)) + '/fixtures')
command = daemon.get_haproxy_command("start")
assert command == "/usr/sbin/haproxy -W -f /etc/haproxy/haproxy.cfg -f %s -p /run/haproxy.pid -S /var/run/haproxy.sock" % (os.path.dirname(__file__) + "/fixtures")
def test_daemonize_haproxy_get_haproxy_command_reload():
tmp_pid_file = "/tmp/tmp_pid.txt"
Functions.save(tmp_pid_file, "10")
try:
daemon = DaemonizeHAProxy(os.path.abspath(os.path.dirname(__file__)) + '/fixtures')
command = daemon.get_haproxy_command("reload", tmp_pid_file)
assert command == "/usr/sbin/haproxy -W -f /etc/haproxy/haproxy.cfg -f %s -p %s -x /var/run/haproxy.sock -sf %s" % (os.path.dirname(__file__) + "/fixtures", tmp_pid_file, 10)
finally:
os.remove(tmp_pid_file)

View file

@ -100,7 +100,7 @@ def test_processor_docker():
'hostssl.local.pem': 'Some PEM Certificate'
}
finally:
os.environ['EASYHAPROXY_CERTBOT_EMAIL'] = ''
del os.environ['EASYHAPROXY_CERTBOT_EMAIL']
container.stop()
container2.stop()

View file

@ -13,15 +13,15 @@ def test_functions_check_local_level():
os.environ['CERTBOT_LOG_LEVEL'] = 'warn'
assert Functions.skip_log('CERTBOT', Functions.INFO) == True
os.environ['CERTBOT_LOG_LEVEL'] = ''
del os.environ['CERTBOT_LOG_LEVEL']
os.environ['HAPROXY_LOG_LEVEL'] = 'warn'
assert Functions.skip_log('HAPROXY', Functions.INFO) == True
os.environ['HAPROXY_LOG_LEVEL'] = ''
del os.environ['HAPROXY_LOG_LEVEL']
os.environ['EASYHAPROXY_LOG_LEVEL'] = 'warn'
assert Functions.skip_log('EASYHAPROXY', Functions.INFO) == True
os.environ['EASYHAPROXY_LOG_LEVEL'] = ''
del os.environ['EASYHAPROXY_LOG_LEVEL']
def test_function_load_and_save():
@ -57,7 +57,7 @@ def test_functions_check_log_sanity():
assert len(Functions.debug_log) == 2
finally:
os.environ['EASYHAPROXY_LOG_LEVEL'] = ''
del os.environ['EASYHAPROXY_LOG_LEVEL']
Functions.debug_log = None

View file

@ -115,10 +115,11 @@ def test_parser_finds_services_raw():
parsed_object = [
{
"mode":"tcp",
"health-check": "",
"ssl-check":"",
"port":"31339",
"hosts":{
"agent.quantum.example.org": {
"balance": "roundrobin",
"containers": [
"my-stack_agent:9001"
],
@ -132,10 +133,11 @@ def test_parser_finds_services_raw():
},
{
"mode":"http",
"health-check": "",
"ssl-check":"",
"port":"31337",
"hosts":{
"cadvisor.quantum.example.org":{
"balance": "roundrobin",
"containers": [
"my-stack_cadvisor:8080"
],
@ -143,6 +145,7 @@ def test_parser_finds_services_raw():
"redirect_ssl": False
},
"node-exporter.quantum.example.org":{
"balance": "roundrobin",
"containers": [
"my-stack_node-exporter:9100"
],
@ -156,10 +159,11 @@ def test_parser_finds_services_raw():
},
{
"mode":"http",
"health-check": "",
"ssl-check":"",
"port":"443",
"hosts":{
"node-exporter.quantum.example.org": {
"balance": "roundrobin",
"containers": [
"my-stack_node-exporter:9100"
],
@ -167,6 +171,7 @@ def test_parser_finds_services_raw():
"redirect_ssl": False
},
"www.somehost.com.br":{
"balance": "roundrobin",
"containers": [
"some-service:80"
],
@ -185,10 +190,11 @@ def test_parser_finds_services_raw():
},
{
"mode":"http",
"health-check": "",
"ssl-check":"",
"port":"80",
"hosts":{
"www.somehost.com.br":{
"balance": "roundrobin",
"containers": [
"some-service:80"
],
@ -451,9 +457,10 @@ def test_parser_finds_services_clone_to_ssl_raw():
parsed_object = [
{
"health-check": "",
"ssl-check":"",
"hosts":{
"host2.local":{
"balance":"roundrobin",
"containers":[
"10.152.183.215:8080"
],
@ -461,6 +468,7 @@ def test_parser_finds_services_clone_to_ssl_raw():
"redirect_ssl": False
},
"valida.me":{
"balance":"roundrobin",
"containers":[
"10.152.183.62:8080"
],
@ -468,6 +476,7 @@ def test_parser_finds_services_clone_to_ssl_raw():
"redirect_ssl": False
},
"www.valida.me":{
"balance":"roundrobin",
"containers":[
"10.152.183.62:8080"
],
@ -482,9 +491,10 @@ def test_parser_finds_services_clone_to_ssl_raw():
}
},
{
"health-check": "ssl",
"ssl-check":"ssl",
"hosts":{
"host2.local":{
"balance":"roundrobin",
"containers":[
"10.152.183.215:8080"
],