1
0
Fork 0

Refactor: modernize codebase by replacing deprecated patterns, simplifying imports, and applying type hinting refinements.

This commit is contained in:
Joao Gilberto Magalhaes 2026-01-22 21:47:33 -05:00
parent 55d0d1a105
commit 62e5c054f4
18 changed files with 75 additions and 68 deletions

View file

@ -16,6 +16,10 @@ sync:
lint:
uv run ruff check src/ tests/
.PHONY: fix
fix:
uv run ruff check --fix src/ tests/
.PHONY: format
format:
uv run ruff format src/ tests/

View file

@ -4,6 +4,7 @@ import os
import re
from jinja2 import Environment, FileSystemLoader
from functions import loggerEasyHaproxy
@ -17,7 +18,7 @@ class DockerLabelHandler:
def create(self, key):
if isinstance(key, str):
return "{}.{}".format(self.__label_base, key)
return f"{self.__label_base}.{key}"
return "{}.{}".format(self.__label_base, ".".join(key))
@ -209,7 +210,7 @@ class HaproxyConfigGenerator:
if socket_path:
server_address = socket_path
else:
server_address = "{}:{}".format(container, ct_port)
server_address = f"{container}:{ct_port}"
easymapping[port]["hosts"][hostname]["containers"] += [server_address]
easymapping[port]["hosts"][hostname]["certbot"] = certbot
@ -306,7 +307,7 @@ class HaproxyConfigGenerator:
# handle SSL
ssl_label = self.label.create([definition, "sslcert"])
if self.label.has_label(ssl_label):
filename = "{}.pem".format(d[host_label])
filename = f"{d[host_label]}.pem"
easymapping[port]["ssl"] = True if not clone_to_ssl else False
self.certs[filename] = base64.b64decode(d[ssl_label]).decode('ascii')

View file

@ -1,16 +1,18 @@
import logging
import os
import shlex
import subprocess
import sys
import psutil
import time
import logging
from datetime import datetime
from multiprocessing import Process
from typing import Final
import psutil
import requests
from OpenSSL import crypto
class ContainerEnv:
@staticmethod
def read():
@ -150,7 +152,7 @@ class Functions:
@staticmethod
def load(filename):
with open(filename, 'r') as content_file:
with open(filename) as content_file:
return content_file.read()
@staticmethod
@ -384,7 +386,7 @@ class Certbot:
)
if self.certbot_manual_auth_hook:
certbot_certonly += ' --manual --manual-auth-hook \'{hook}\''.format(hook=self.certbot_manual_auth_hook)
certbot_certonly += f' --manual --manual-auth-hook \'{self.certbot_manual_auth_hook}\''
if loggerCertbot.level == logging.DEBUG:
certbot_certonly += ' -v'

View file

@ -2,8 +2,14 @@ import os
from deepdiff import DeepDiff
from functions import Functions, DaemonizeHAProxy, Certbot, Consts, loggerInit, loggerEasyHaproxy, loggerHaproxy, \
loggerCertbot
from functions import (
Certbot,
Consts,
DaemonizeHAProxy,
Functions,
loggerEasyHaproxy,
loggerInit,
)
from processor import ProcessorInterface
@ -69,7 +75,7 @@ def main():
loggerInit.debug('Environment:')
for name, value in os.environ.items():
if "HAPROXY" in name:
loggerInit.debug("- {0}: {1}".format(name, value))
loggerInit.debug(f"- {name}: {value}")
start()

View file

@ -1,10 +1,11 @@
import os
import importlib.util
import os
import sys
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional, Dict, Any, List
from typing import Any, Dict, List, Optional
from functions import loggerEasyHaproxy
@ -20,17 +21,17 @@ class PluginContext:
parsed_object: dict # {IP: labels} from discovery
easymapping: list # Current HAProxy mapping structure
container_env: dict # Environment configuration
domain: Optional[str] = None # Domain name (for DOMAIN plugins)
port: Optional[str] = None # Port (for DOMAIN plugins)
host_config: Optional[dict] = None # Domain-specific config
domain: str | None = None # Domain name (for DOMAIN plugins)
port: str | None = None # Port (for DOMAIN plugins)
host_config: dict | None = None # Domain-specific config
@dataclass
class PluginResult:
"""Plugin execution result"""
haproxy_config: str = "" # HAProxy config snippet to inject
modified_easymapping: Optional[list] = None # Modified easymapping structure
metadata: Dict[str, Any] = field(default_factory=dict) # Plugin metadata for logging
modified_easymapping: list | None = None # Modified easymapping structure
metadata: dict[str, Any] = field(default_factory=dict) # Plugin metadata for logging
class PluginInterface(ABC):
@ -85,9 +86,9 @@ class PluginManager:
"""
self.plugins_dir = plugins_dir
self.abort_on_error = abort_on_error
self.plugins: Dict[str, PluginInterface] = {}
self.global_plugins: List[PluginInterface] = []
self.domain_plugins: List[PluginInterface] = []
self.plugins: dict[str, PluginInterface] = {}
self.global_plugins: list[PluginInterface] = []
self.domain_plugins: list[PluginInterface] = []
self.logger = loggerEasyHaproxy
def load_plugins(self) -> None:
@ -174,7 +175,7 @@ class PluginManager:
except Exception as e:
self._handle_error(f"Failed to configure plugin '{plugin_name}': {str(e)}")
def execute_global_plugins(self, context: PluginContext, enabled_list: Optional[List[str]] = None) -> List[PluginResult]:
def execute_global_plugins(self, context: PluginContext, enabled_list: list[str] | None = None) -> list[PluginResult]:
"""
Execute all global plugins
@ -205,7 +206,7 @@ class PluginManager:
return results
def execute_domain_plugins(self, context: PluginContext, enabled_list: Optional[List[str]] = None) -> List[PluginResult]:
def execute_domain_plugins(self, context: PluginContext, enabled_list: list[str] | None = None) -> list[PluginResult]:
"""
Execute all domain plugins for a specific domain

View file

@ -21,16 +21,16 @@ Example Environment Variable:
EASYHAPROXY_PLUGIN_CLEANUP_MAX_IDLE_TIME=600
"""
import glob
import os
import sys
import glob
import time
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from plugins import PluginInterface, PluginType, PluginContext, PluginResult
from functions import loggerEasyHaproxy
from plugins import PluginContext, PluginInterface, PluginResult, PluginType
class CleanupPlugin(PluginInterface):

View file

@ -33,8 +33,8 @@ import sys
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from plugins import PluginInterface, PluginType, PluginContext, PluginResult
from functions import loggerEasyHaproxy
from plugins import PluginContext, PluginInterface, PluginResult, PluginType
class CloudflarePlugin(PluginInterface):

View file

@ -32,7 +32,7 @@ import sys
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from plugins import PluginInterface, PluginType, PluginContext, PluginResult
from plugins import PluginContext, PluginInterface, PluginResult, PluginType
class DenyPagesPlugin(PluginInterface):

View file

@ -42,8 +42,7 @@ import sys
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from plugins import PluginInterface, PluginType, PluginContext, PluginResult
from functions import loggerEasyHaproxy
from plugins import PluginContext, PluginInterface, PluginResult, PluginType
class FastcgiPlugin(PluginInterface):
@ -124,7 +123,7 @@ class FastcgiPlugin(PluginInterface):
# PATH_INFO support
if self.path_info:
fcgi_app_lines.append(f" path-info ^(/.+\\.php)(/.*)?$")
fcgi_app_lines.append(" path-info ^(/.+\\.php)(/.*)?$")
# Set SCRIPT_FILENAME if customized
if self.script_filename and self.script_filename != "%[path]":

View file

@ -33,7 +33,7 @@ import sys
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from plugins import PluginInterface, PluginType, PluginContext, PluginResult
from plugins import PluginContext, PluginInterface, PluginResult, PluginType
class IpWhitelistPlugin(PluginInterface):

View file

@ -74,8 +74,8 @@ import sys
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from plugins import PluginInterface, PluginType, PluginContext, PluginResult
from functions import loggerEasyHaproxy
from plugins import PluginContext, PluginInterface, PluginResult, PluginType
class JwtValidatorPlugin(PluginInterface):

View file

@ -8,8 +8,7 @@ from kubernetes import client, config
from kubernetes.client.rest import ApiException
from easymapping import HaproxyConfigGenerator
from functions import Functions, Consts, ContainerEnv
from functions import loggerEasyHaproxy
from functions import Consts, ContainerEnv, Functions, loggerEasyHaproxy
class ProcessorInterface:
@ -87,7 +86,7 @@ class ProcessorInterface:
def save_certs(self, path):
for cert in self.get_certs():
Functions.save("{0}/{1}".format(path, cert), self.get_certs(cert))
Functions.save(f"{path}/{cert}", self.get_certs(cert))
class Static(ProcessorInterface):
@ -502,7 +501,7 @@ class Kubernetes(ProcessorInterface):
if tls.secret_name not in self.cert_cache or self.cert_cache[tls.secret_name] != secret.data:
self.cert_cache[tls.secret_name] = secret.data
Functions.save(
"{0}/{1}.pem".format(Consts.certs_haproxy, tls.secret_name),
f"{Consts.certs_haproxy}/{tls.secret_name}.pem",
base64.b64decode(secret.data["tls.crt"]).decode('ascii') + "\n" + base64.b64decode(
secret.data["tls.key"]).decode('ascii')
)

View file

@ -1,6 +1,6 @@
import os
from functions import Functions, ContainerEnv
from functions import ContainerEnv, Functions
def test_container_env_empty():

View file

@ -1,8 +1,6 @@
import os
import psutil
from functions import DaemonizeHAProxy, Functions
from functions import DaemonizeHAProxy
def test_daemonize_haproxy():

View file

@ -1,14 +1,11 @@
import logging
import os
import random
import re
import string
from logging import Logger
from functions import Functions, loggerEasyHaproxy, loggerCertbot, loggerHaproxy
from io import StringIO
from functions import Functions, loggerCertbot, loggerEasyHaproxy, loggerHaproxy
log_stream = StringIO() # Create StringIO object
log_handler = logging.StreamHandler(log_stream)
log_formatter = logging.Formatter('%(levelname)s - %(message)s')

View file

@ -12,7 +12,7 @@ CERTBOT_EMAIL = "some@email.com"
def load_fixture(file):
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/fixtures/" + file, 'r') as content_file:
with open(path + "/fixtures/" + file) as content_file:
line_list = json.loads("".join(content_file.readlines()))
return line_list
@ -33,7 +33,7 @@ def test_parser_doesnt_crash():
assert len(haproxy_config) > 0
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/expected/no-services.txt", 'r') as expected_file:
with open(path + "/expected/no-services.txt") as expected_file:
assert expected_file.read() == haproxy_config
assert [] == cfg.certbot_hosts
@ -56,7 +56,7 @@ def test_parser_finds_services():
assert len(haproxy_config) > 0
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/expected/services.txt", 'r') as expected_file:
with open(path + "/expected/services.txt") as expected_file:
assert expected_file.read() == haproxy_config
assert {"www.somehost.com.br.pem": "Some PEM Certificate"} == cfg.certs
@ -86,7 +86,7 @@ def test_parser_finds_services_changed_label():
assert len(haproxy_config) > 0
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/expected/services.txt", 'r') as expected_file:
with open(path + "/expected/services.txt") as expected_file:
assert expected_file.read() == haproxy_config
assert {"www.somehost.com.br.pem": "Some PEM Certificate"} == cfg.certs
@ -232,21 +232,21 @@ def test_parser_finds_services_raw():
def test_parser_static():
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/fixtures/static.yml", 'r') as content_file:
with open(path + "/fixtures/static.yml") 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
with open(path + "/expected/static.txt", 'r') as expected_file:
with open(path + "/expected/static.txt") as expected_file:
assert expected_file.read() == haproxy_config
assert [] == cfg.certbot_hosts
def test_parser_static_raw():
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/fixtures/static.yml", 'r') as content_file:
with open(path + "/fixtures/static.yml") as content_file:
parsed = yaml.load(content_file.read(), Loader=yaml.FullLoader)
expected = {
@ -319,7 +319,7 @@ def test_parser_tcp():
assert len(haproxy_config) > 0
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/expected/services-tcp.txt", 'r') as expected_file:
with open(path + "/expected/services-tcp.txt") as expected_file:
assert expected_file.read() == haproxy_config
assert [] == cfg.certbot_hosts
@ -339,7 +339,7 @@ def test_parser_multi_containers():
assert len(haproxy_config) > 0
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/expected/services-multi-containers.txt", 'r') as expected_file:
with open(path + "/expected/services-multi-containers.txt") as expected_file:
assert expected_file.read() == haproxy_config
assert [] == cfg.certbot_hosts
@ -361,7 +361,7 @@ def test_parser_multiple_hosts():
assert len(haproxy_config) > 0
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/expected/services-multiple-hosts.txt", 'r') as expected_file:
with open(path + "/expected/services-multiple-hosts.txt") as expected_file:
assert expected_file.read() == haproxy_config
assert [] == cfg.certbot_hosts
@ -382,7 +382,7 @@ def test_parser_redirect_ssl():
assert len(haproxy_config) > 0
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/expected/services-redirect-ssl.txt", 'r') as expected_file:
with open(path + "/expected/services-redirect-ssl.txt") as expected_file:
assert expected_file.read() == haproxy_config
assert [] == cfg.certbot_hosts
@ -403,7 +403,7 @@ def test_parser_ssl_strict():
assert len(haproxy_config) > 0
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/expected/ssl-strict.txt", 'r') as expected_file:
with open(path + "/expected/ssl-strict.txt") as expected_file:
assert expected_file.read() == haproxy_config
assert [] == cfg.certbot_hosts
@ -421,7 +421,7 @@ def test_parser_ssl_loose():
assert len(haproxy_config) > 0
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/expected/ssl-loose.txt", 'r') as expected_file:
with open(path + "/expected/ssl-loose.txt") as expected_file:
assert expected_file.read() == haproxy_config
assert [] == cfg.certbot_hosts
@ -444,7 +444,7 @@ def test_parser_ssl_letsencrypt():
assert len(haproxy_config) > 0
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/expected/services-letsencrypt.txt", 'r') as expected_file:
with open(path + "/expected/services-letsencrypt.txt") as expected_file:
assert expected_file.read() == haproxy_config
assert ["test.example.org"] == cfg.certbot_hosts
@ -561,7 +561,7 @@ def test_parser_fcgi():
assert "172.17.0.3:9000" in haproxy_config
path = os.path.dirname(os.path.realpath(__file__))
with open(path + "/expected/services-fcgi.txt", 'r') as expected_file:
with open(path + "/expected/services-fcgi.txt") as expected_file:
assert expected_file.read() == haproxy_config
assert [] == cfg.certbot_hosts

View file

@ -7,29 +7,29 @@ Tests all builtin plugins:
- DenyPagesPlugin (domain)
"""
import json
import os
import sys
import json
import tempfile
import time
# Add src to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from plugins import PluginManager, PluginContext
from plugins.builtin.cloudflare import CloudflarePlugin
import easymapping
from plugins import PluginContext, PluginManager
from plugins.builtin.cleanup import CleanupPlugin
from plugins.builtin.cloudflare import CloudflarePlugin
from plugins.builtin.deny_pages import DenyPagesPlugin
from plugins.builtin.fastcgi import FastcgiPlugin
from plugins.builtin.ip_whitelist import IpWhitelistPlugin
from plugins.builtin.jwt_validator import JwtValidatorPlugin
from plugins.builtin.fastcgi import FastcgiPlugin
import easymapping
def load_fixture(file):
"""Load a test fixture"""
fixture_path = os.path.join(os.path.dirname(__file__), "fixtures", file)
with open(fixture_path, 'r') as content_file:
with open(fixture_path) as content_file:
line_list = json.loads("".join(content_file.readlines()))
return line_list
@ -160,7 +160,7 @@ class TestCloudflarePlugin:
assert os.path.exists(ip_list_path)
# Verify file contains correct number of IPs
with open(ip_list_path, 'r') as f:
with open(ip_list_path) as f:
lines = [line.strip() for line in f if line.strip()]
assert len(lines) == 22
# Verify some known Cloudflare IPs are in the file