From 166b75cd754b0ce4ce6d3a18794ca713ee9d8f08 Mon Sep 17 00:00:00 2001 From: Joao Gilberto Magalhaes Date: Mon, 3 Jul 2023 14:59:17 -0500 Subject: [PATCH] Minor Fix Pre-Merge --- docs/kubernetes.md | 19 +++++----- docs/volumes.md | 14 ++++---- examples/swarm/easyhaproxy.yml | 4 +-- examples/swarm/portainer.yml | 4 +-- src/functions/__init__.py | 18 +++++++--- src/processor/__init__.py | 2 +- src/templates/bind.j2 | 2 +- src/tests/expected/docker.txt | 2 +- src/tests/expected/services-letsencrypt.txt | 2 +- src/tests/expected/services-redirect-ssl.txt | 2 +- src/tests/expected/services.txt | 2 +- src/tests/expected/static.txt | 2 +- src/tests/test_containerenv.py | 37 +++++++++++--------- src/tests/test_daemonize.py | 22 +++++++----- src/tests/test_docker.py | 2 +- src/tests/test_functions.py | 8 ++--- 16 files changed, 77 insertions(+), 65 deletions(-) diff --git a/docs/kubernetes.md b/docs/kubernetes.md index 9354b91..b3fac3c 100644 --- a/docs/kubernetes.md +++ b/docs/kubernetes.md @@ -79,17 +79,14 @@ Notes: ## 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.letsencrypt | (optional) Boolean. It will request letsencrypt certificates for the ingresses domains. | false | true or false | -| easyhaproxy.redirect | (optional) JSON. Key pair with a domain and its destination. | *empty* | {"domain":"redirect_url"} | -| easyhaproxy.mode | (optional) Set the HTTP mode for that connection. | http | http or tcp | -| easyhaproxy.listen_port | (optional) Set the an additional port for that ingress | http | http or tcp | -| easyhaproxt.logLevel.certbot | (optional) Certbot log level | DEBUG | TRACE,DEBUG,INFO,WARN,ERROR or FATAL | -| easyhaproxt.logLevel.eashhaproxy | (optional) EasyHAProxy log level | DEBUG | TRACE,DEBUG,INFO,WARN,ERROR or FATAL | -| easyhaproxt.logLevel.haproxy | (optional) HAProxy log level | INFO | TRACE,DEBUG,INFO,WARN,ERROR or FATAL | +| 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 | +| easyhaproxy.redirect | (optional) JSON. Key pair with a domain and its destination. | *empty* | {"domain":"redirect_url"} | +| easyhaproxy.mode | (optional) Set the HTTP mode for that connection. | http | http or tcp | +| easyhaproxy.listen_port | (optional) Set the an additional port for that ingress | http | http or tcp | **Important**: The annotations are per ingress and applied to all hosts in that ingress configuration. diff --git a/docs/volumes.md b/docs/volumes.md index 4413095..47daa02 100644 --- a/docs/volumes.md +++ b/docs/volumes.md @@ -2,13 +2,13 @@ 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/letsencrypt/ | The folder that will contain the certificates (`PEM`) for the SSL. Use this volume to cache the [letsencrypt](letsencrypt.md) certificate and avoid re-issue certificates between restarts. | -| /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. | +| 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) diff --git a/examples/swarm/easyhaproxy.yml b/examples/swarm/easyhaproxy.yml index 3d088ef..a15260b 100644 --- a/examples/swarm/easyhaproxy.yml +++ b/examples/swarm/easyhaproxy.yml @@ -11,7 +11,7 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock - ./certs:/certs/haproxy - - certs_letsencrypt:/certs/letsencrypt + - certs_certbot:/certs/certbot deploy: replicas: 1 environment: @@ -34,7 +34,7 @@ networks: external: true volumes: - certs_letsencrypt: + certs_certbot: # external: true # certs_haproxy: # external: true \ No newline at end of file diff --git a/examples/swarm/portainer.yml b/examples/swarm/portainer.yml index b438b58..d259988 100644 --- a/examples/swarm/portainer.yml +++ b/examples/swarm/portainer.yml @@ -13,13 +13,13 @@ services: replicas: 1 labels: # easyhaproxy.http.redirect_ssl: true - # easyhaproxy.http.letsencrypt: true + # easyhaproxy.http.certbot: true easyhaproxy.http.host: portainer.local easyhaproxy.http.port: 80 easyhaproxy.http.localport: 9000 volumes: - certs_letsencrypt: + certs_certbot: external: true # certs_haproxy: # external: true diff --git a/src/functions/__init__.py b/src/functions/__init__.py index 70f8ed8..1b3b1c0 100644 --- a/src/functions/__init__.py +++ b/src/functions/__init__.py @@ -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"] @@ -195,16 +202,17 @@ class DaemonizeHAProxy: self.thread = Process(target=self.__start, args=()) self.thread.start() - def get_haproxy_command(self, action): + 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 /run/haproxy.pid -S /var/run/haproxy.sock" % (custom_config_files) + return "/usr/sbin/haproxy -W -f /etc/haproxy/haproxy.cfg %s -p %s -S /var/run/haproxy.sock" % (custom_config_files, pid_file) else: - pid = "".join(Functions().run_bash(Functions.HAPROXY_LOG, "cat /run/haproxy.pid", log_output=False)) - return "/usr/sbin/haproxy -W -f /etc/haproxy/haproxy.cfg %s -p /run/haproxy.pid -x /var/run/haproxy.sock -sf %s" % (custom_config_files, pid) + 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 diff --git a/src/processor/__init__.py b/src/processor/__init__.py index 5373b75..0d3f8a5 100644 --- a/src/processor/__init__.py +++ b/src/processor/__init__.py @@ -198,7 +198,7 @@ class Kubernetes(ProcessorInterface): self.cert_cache = {} super().__init__() - def _check_annotation(self, annotations, key, default = None): + def _check_annotation(self, annotations, key, default=None): if key not in annotations: return default return annotations[key] diff --git a/src/templates/bind.j2 b/src/templates/bind.j2 index e4f264e..d69de8f 100644 --- a/src/templates/bind.j2 +++ b/src/templates/bind.j2 @@ -1,5 +1,5 @@ {% if "ssl" in o %} - bind *:{{ o["port"] }} ssl crt /certs/letsencrypt/ alpn h2,http/1.1 crt /certs/haproxy/ alpn h2,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 diff --git a/src/tests/expected/docker.txt b/src/tests/expected/docker.txt index 92c7430..91f928b 100644 --- a/src/tests/expected/docker.txt +++ b/src/tests/expected/docker.txt @@ -36,7 +36,7 @@ backend srv_stats server Local 127.0.0.1:1936 frontend http_in_443 - bind *:443 ssl crt /certs/letsencrypt/ alpn h2,http/1.1 crt /certs/haproxy/ alpn h2,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 diff --git a/src/tests/expected/services-letsencrypt.txt b/src/tests/expected/services-letsencrypt.txt index ff7dd8c..8d5da5d 100644 --- a/src/tests/expected/services-letsencrypt.txt +++ b/src/tests/expected/services-letsencrypt.txt @@ -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/letsencrypt/ alpn h2,http/1.1 crt /certs/haproxy/ alpn h2,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 diff --git a/src/tests/expected/services-redirect-ssl.txt b/src/tests/expected/services-redirect-ssl.txt index 01c9c09..ad841cc 100644 --- a/src/tests/expected/services-redirect-ssl.txt +++ b/src/tests/expected/services-redirect-ssl.txt @@ -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/letsencrypt/ alpn h2,http/1.1 crt /certs/haproxy/ alpn h2,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 diff --git a/src/tests/expected/services.txt b/src/tests/expected/services.txt index f6aaf6a..82f8a6c 100644 --- a/src/tests/expected/services.txt +++ b/src/tests/expected/services.txt @@ -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/letsencrypt/ alpn h2,http/1.1 crt /certs/haproxy/ alpn h2,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 } diff --git a/src/tests/expected/static.txt b/src/tests/expected/static.txt index b643379..a5af1ec 100644 --- a/src/tests/expected/static.txt +++ b/src/tests/expected/static.txt @@ -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/letsencrypt/ alpn h2,http/1.1 crt /certs/haproxy/ alpn h2,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 diff --git a/src/tests/test_containerenv.py b/src/tests/test_containerenv.py index 9a3f3aa..30c2680 100644 --- a/src/tests/test_containerenv.py +++ b/src/tests/test_containerenv.py @@ -13,7 +13,7 @@ def test_container_env_empty(): "haproxy": Functions.INFO, "certbot": Functions.DEBUG, }, - "certbot": {"autoconfig": "", + "certbot": {"autoconfig": "", "eab_hmac_key": "", "eab_kid": "", "email": "", @@ -44,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(): @@ -67,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(): @@ -91,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(): @@ -121,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(): @@ -151,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(): @@ -178,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(): @@ -192,10 +192,6 @@ def test_container_env_certbot_full(): "customerrors": False, "ssl_mode": "default", "lookup_label": "easyhaproxy", - "letsencrypt": { - "email": "acme@example.org", - "server": True - }, "logLevel": { "easyhaproxy": Functions.DEBUG, "haproxy": Functions.INFO, @@ -211,7 +207,12 @@ def test_container_env_certbot_full(): } } == ContainerEnv.read() finally: - os.environ['EASYHAPROXY_LETSENCRYPT_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 @@ -231,10 +232,12 @@ def test_container_log_level(): "autoconfig": "", 'eab_hmac_key': "", 'eab_kid': "", - "email": "acme@example.org", + "email": "", "server": False, "retry_count": 60 } } == ContainerEnv.read() finally: - os.environ['EASYHAPROXY_CERTBOT_EMAIL'] = '' + del os.environ['CERTBOT_LOG_LEVEL'] + del os.environ['EASYHAPROXY_LOG_LEVEL'] + del os.environ['HAPROXY_LOG_LEVEL'] diff --git a/src/tests/test_daemonize.py b/src/tests/test_daemonize.py index fb1ea08..e5d87c9 100644 --- a/src/tests/test_daemonize.py +++ b/src/tests/test_daemonize.py @@ -1,10 +1,7 @@ -import json -import pytest import os -import re -import random -import string -from functions import DaemonizeHAProxy + +from functions import DaemonizeHAProxy, Functions + def test_daemonize_haproxy(): daemon = DaemonizeHAProxy() @@ -38,7 +35,14 @@ def test_daemonize_haproxy_get_haproxy_command_start(): 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(): - daemon = DaemonizeHAProxy(os.path.abspath(os.path.dirname(__file__)) + '/fixtures') - command = daemon.get_haproxy_command("reload") - assert command == "/usr/sbin/haproxy -W -f /etc/haproxy/haproxy.cfg -f %s -p /run/haproxy.pid -x /var/run/haproxy.sock -sf " % (os.path.dirname(__file__) + "/fixtures") + 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) diff --git a/src/tests/test_docker.py b/src/tests/test_docker.py index b6b95e1..e31063e 100644 --- a/src/tests/test_docker.py +++ b/src/tests/test_docker.py @@ -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() diff --git a/src/tests/test_functions.py b/src/tests/test_functions.py index e31a0ea..770cd55 100644 --- a/src/tests/test_functions.py +++ b/src/tests/test_functions.py @@ -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