Skip to content

Commit

Permalink
Merge pull request #58
Browse files Browse the repository at this point in the history
Log Refactor
  • Loading branch information
byjg authored Nov 19, 2024
2 parents 5ac73de + d8049f3 commit 64bc49b
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 176 deletions.
135 changes: 68 additions & 67 deletions src/functions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import os
import shlex
import subprocess
import sys
import time
import logging
from datetime import datetime
from multiprocessing import Process
from typing import Final

import requests
from OpenSSL import crypto


class ContainerEnv:
@staticmethod
def read():
Expand Down Expand Up @@ -82,42 +84,45 @@ def read():
env_vars["certbot"]["eab_hmac_key"] = os.environ['EASYHAPROXY_CERTBOT_EAB_HMAC_KEY'] = resp["eab_hmac_key"]
else:
del os.environ["EASYHAPROXY_CERTBOT_EMAIL"]
Functions.log(Functions.CERTBOT_LOG, Functions.ERROR, "Could not obtain ZeroSSL credentials " + resp["error"]["type"])
loggerCertbot.error("Could not obtain ZeroSSL credentials " + resp["error"]["type"])

os.environ['EASYHAPROXY_CERTBOT_SERVER'] = env_vars["certbot"]["server"]

return env_vars


class Functions:
HAPROXY_LOG = "HAPROXY"
EASYHAPROXY_LOG = "EASYHAPROXY"
CERTBOT_LOG = "CERTBOT"
INIT_LOG = "INIT"

TRACE = "TRACE"
DEBUG = "DEBUG"
INFO = "INFO"
WARN = "WARN"
ERROR = "ERROR"
FATAL = "FATAL"

debug_log = None
HAPROXY_LOG: Final[str] = "HAPROXY"
EASYHAPROXY_LOG: Final[str] = "EASYHAPROXY"
CERTBOT_LOG: Final[str] = "CERTBOT"
INIT_LOG: Final[str] = "INIT"

TRACE: Final[str] = "TRACE"
DEBUG: Final[str] = "DEBUG"
INFO: Final[str] = "INFO"
WARN: Final[str] = "WARN"
ERROR: Final[str] = "ERROR"
FATAL: Final[str] = "FATAL"

@staticmethod
def skip_log(source, log_level_str):
level = os.getenv("%s_LOG_LEVEL" % (source.upper()), "").upper()
def setup_log(source):
level = os.getenv("%s_LOG_LEVEL" % (source.name.upper()), "").upper()
level_importance = {
Functions.TRACE: 0,
Functions.DEBUG: 1,
Functions.INFO: 2,
Functions.WARN: 3,
Functions.ERROR: 4,
Functions.FATAL: 5
Functions.TRACE: logging.DEBUG,
Functions.DEBUG: logging.DEBUG,
Functions.INFO: logging.INFO,
Functions.WARN: logging.WARNING,
Functions.ERROR: logging.ERROR,
Functions.FATAL: logging.FATAL
}
level_required = 1 if level not in level_importance else level_importance[level]
level_asked = 1 if log_level_str.upper() not in level_importance else level_importance[log_level_str.upper()]
return level_asked < level_required
selected_level = level_importance[level] if level in level_importance else logging.INFO

log_source_handler = logging.StreamHandler(sys.stdout)
log_source_formatter = logging.Formatter('%(name)s [%(asctime)s] %(levelname)s - %(message)s')
log_source_handler.setFormatter(log_source_formatter)
source.setLevel(selected_level)
source.addHandler(log_source_handler)
return selected_level

@staticmethod
def load(filename):
Expand All @@ -130,24 +135,7 @@ def save(filename, contents):
file.write(contents)

@staticmethod
def log(source, level, message):
if message is None or message == "":
return

if Functions.skip_log(source, level):
return

if not isinstance(message, (list, tuple)):
message = [message]

for line in message:
log = "[%s] %s [%s]: %s" % (source, datetime.now().strftime("%x %X"), level, line.rstrip())
print(log)
if Functions.debug_log is not None:
Functions.debug_log.append(log)

@staticmethod
def run_bash(source, command, log_output=True, return_result=True):
def run_bash(log_source, command, log_output=True, return_result=True):
if not isinstance(command, (list, tuple)):
command = shlex.split(command)

Expand All @@ -161,22 +149,24 @@ def run_bash(source, command, log_output=True, return_result=True):

while True:
line = process.stdout.readline().rstrip()
error_line = process.stderr.readline().rstrip()
output.append(line) if return_result else None
Functions.log(source, Functions.INFO, line) if log_output else None
Functions.log(source, Functions.WARN, process.stderr.readline())
log_source.info(line) if log_output and len(line) > 0 else None
log_source.warning(error_line) if len(error_line) > 0 else None
return_code = process.poll()
if return_code is not None:
lines = []
error_line = process.stderr.readline().rstrip()
for line in process.stdout.readlines():
output.append(line.rstrip()) if return_result else None
lines.append(line.rstrip())
Functions.log(source, Functions.INFO, lines) if log_output else None
Functions.log(source, Functions.WARN, process.stderr.readlines())
log_source.info(lines) if log_output and len(lines) > 0 else None
log_source.warning(error_line) if len(error_line) > 0 else None
break

return [return_code, output]
except Exception as e:
Functions.log(source, Functions.ERROR, "%s" % e)
log_source.error("%s" % e)
return [-99, e]


Expand All @@ -189,6 +179,9 @@ class Consts:


class DaemonizeHAProxy:
HAPROXY_START: Final[str] = "start"
HAPROXY_RELOAD: Final[str] = "reload"

def __init__(self, custom_config_folder = None):
self.process = None
self.thread = None
Expand All @@ -207,17 +200,16 @@ def haproxy(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)
custom_config_files = "-f %s" % self.custom_config_folder

if action == "start":
if action == DaemonizeHAProxy.HAPROXY_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)
return_code, output = Functions().run_bash(loggerHaproxy, "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)):
command = shlex.split(command)

Expand All @@ -230,20 +222,19 @@ def __prepare(self, command):
universal_newlines=True)

except Exception as e:
Functions.log(source, Functions.ERROR, "%s" % e)
loggerHaproxy.error("%s" % e)

def __start(self):
source = Functions.HAPROXY_LOG
try:
with self.process.stdout:
for line in iter(self.process.stdout.readline, b''):
Functions.log(source, Functions.INFO, line)
loggerHaproxy.info(line)

return_code = self.process.wait()
Functions.log(source, Functions.DEBUG, "Return code %s" % return_code)
loggerHaproxy.debug("Return code %s" % return_code)

except Exception as e:
Functions.log(source, Functions.ERROR, "%s" % e)
loggerHaproxy.error("%s" % e)

def is_alive(self):
return self.thread.is_alive()
Expand Down Expand Up @@ -330,14 +321,13 @@ def check_certificates(self, hosts):
elif host in self.freeze_issue:
freeze_count = self.freeze_issue.pop(host, 0)
if freeze_count > 0:
Functions.log(Functions.CERTBOT_LOG, Functions.DEBUG,
"Waiting freezing period (%d) for %s due previous errors" % (freeze_count, host))
loggerCertbot.debug("Waiting freezing period (%d) for %s due previous errors" % (freeze_count, host))
self.freeze_issue[host] = freeze_count-1
elif cert_status == "not_found" or cert_status == "expired":
Functions.log(Functions.CERTBOT_LOG, Functions.DEBUG, "[%s] Request new certificate for %s" % (cert_status, host))
loggerCertbot.debug("[%s] Request new certificate for %s" % (cert_status, host))
request_certs.append(host_arg)
elif cert_status == "expiring":
Functions.log(Functions.CERTBOT_LOG, Functions.DEBUG, "[%s] Renew certificate for %s" % (cert_status, host))
loggerCertbot.debug("[%s] Renew certificate for %s" % (cert_status, host))
renew_certs.append(host_arg)

certbot_certonly = ('/usr/bin/certbot certonly {acme_server}'
Expand Down Expand Up @@ -368,11 +358,11 @@ def check_certificates(self, hosts):
return_code_issue = 0
return_code_renew = 0
if len(request_certs) > 0:
return_code_issue, output = Functions.run_bash(Functions.CERTBOT_LOG, certbot_certonly, return_result=False)
return_code_issue, output = Functions.run_bash(loggerCertbot, certbot_certonly, return_result=False)
ret_reload = True

if len(renew_certs) > 0:
return_code_renew, output = Functions.run_bash(Functions.CERTBOT_LOG, "/usr/bin/certbot renew", return_result=False)
return_code_renew, output = Functions.run_bash(loggerCertbot, "/usr/bin/certbot renew", return_result=False)
ret_reload = True

if ret_reload:
Expand All @@ -385,7 +375,7 @@ def check_certificates(self, hosts):

return ret_reload
except Exception as e:
Functions.log(Functions.CERTBOT_LOG, Functions.ERROR, "%s" % e)
loggerCertbot.error("%s" % e)
return False

@staticmethod
Expand Down Expand Up @@ -420,7 +410,7 @@ def get_certificate_status(self, host):
elif (expiration_after - current_time) // (24 * 3600) <= 15:
return "expiring"
except Exception as e:
Functions.log(Functions.CERTBOT_LOG, Functions.ERROR, "Certificate %s error %s" % (host, e))
loggerCertbot.error("Certificate %s error %s" % (host, e))
return "error"

return "ok"
Expand All @@ -432,4 +422,15 @@ def find_missing_certificates(self, hosts):
cert_status = self.get_certificate_status(host)
if cert_status != "ok":
self.freeze_issue[host] = self.retry_count
Functions.log(Functions.CERTBOT_LOG, Functions.DEBUG, "Freeze issuing ssl for %s due failure. The certificate is %s" % (host, cert_status))
loggerCertbot.debug("Freeze issuing ssl for %s due failure. The certificate is %s" % (host, cert_status))

# ####################################################################################################################
# Setup Global Log
loggerInit = logging.getLogger(Functions.INIT_LOG)
loggerHaproxy = logging.getLogger(Functions.HAPROXY_LOG)
loggerEasyHaproxy = logging.getLogger(Functions.EASYHAPROXY_LOG)
loggerCertbot = logging.getLogger(Functions.CERTBOT_LOG)
Functions.setup_log(loggerInit)
Functions.setup_log(loggerHaproxy)
Functions.setup_log(loggerEasyHaproxy)
Functions.setup_log(loggerCertbot)
43 changes: 21 additions & 22 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import os
import logging

from deepdiff import DeepDiff

from functions import Functions, DaemonizeHAProxy, Certbot, Consts
from functions import Functions, DaemonizeHAProxy, Certbot, Consts, loggerInit, loggerEasyHaproxy, loggerHaproxy, \
loggerCertbot
from processor import ProcessorInterface


Expand All @@ -17,14 +19,13 @@ def start():
processor_obj.save_config(Consts.haproxy_config)
processor_obj.save_certs(Consts.certs_haproxy)
certbot_certs_found = processor_obj.get_certbot_hosts()
Functions.log(Functions.EASYHAPROXY_LOG, Functions.DEBUG,
'Found hosts: %s' % ", ".join(processor_obj.get_hosts())) # Needs to run after save_config
Functions.log(Functions.EASYHAPROXY_LOG, Functions.TRACE, 'Object Found: %s' % (processor_obj.get_parsed_object()))
loggerEasyHaproxy.info('Found hosts: %s' % ", ".join(processor_obj.get_hosts())) # Needs to run after save_config
loggerEasyHaproxy.debug('Object Found: %s' % (processor_obj.get_parsed_object()))

old_haproxy = None
haproxy = DaemonizeHAProxy()
current_custom_config_files = haproxy.get_custom_config_files()
haproxy.haproxy("start")
haproxy.haproxy(DaemonizeHAProxy.HAPROXY_START)
haproxy.sleep()

certbot = Certbot(Consts.certs_certbot)
Expand All @@ -37,41 +38,39 @@ def start():
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() 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()))
loggerEasyHaproxy.info('New configuration found. Reloading...')
loggerEasyHaproxy.debug('Object Found: %s' % (processor_obj.get_parsed_object()))
processor_obj.save_config(Consts.haproxy_config)
processor_obj.save_certs(Consts.certs_haproxy)
certbot_certs_found = processor_obj.get_certbot_hosts()
Functions.log(Functions.EASYHAPROXY_LOG, Functions.DEBUG,
'Found hosts: %s' % ", ".join(processor_obj.get_hosts())) # Needs to after save_config
loggerEasyHaproxy.info('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")
haproxy.haproxy(DaemonizeHAProxy.HAPROXY_RELOAD)
old_haproxy.terminate()

except Exception as e:
Functions.log(Functions.EASYHAPROXY_LOG, Functions.FATAL, "Err: %s" % e)
loggerEasyHaproxy.fatal("Err: %s" % e)

Functions.log(Functions.EASYHAPROXY_LOG, Functions.DEBUG, 'Heartbeat')
loggerEasyHaproxy.info('Heartbeat')
haproxy.sleep()


def main():
Functions.run_bash(Functions.INIT_LOG, '/usr/sbin/haproxy -v')
Functions.run_bash(loggerInit, '/usr/sbin/haproxy -v')

Functions.log(Functions.INIT_LOG, Functions.INFO, " _ ")
Functions.log(Functions.INIT_LOG, Functions.INFO, " ___ __ _ ____ _ ___| |_ __ _ _ __ _ _ _____ ___ _ ")
Functions.log(Functions.INIT_LOG, Functions.INFO, "/ -_) _` (_-< || |___| ' \\/ _` | '_ \\ '_/ _ \\ \\ / || |")
Functions.log(Functions.INIT_LOG, Functions.INFO, "\\___\\__,_/__/\\_, | |_||_\\__,_| .__/_| \\___/_\\_\\_, |")
Functions.log(Functions.INIT_LOG, Functions.INFO, " |__/ |_| |__/ ")
loggerInit.info(" _ ")
loggerInit.info(" ___ __ _ ____ _ ___| |_ __ _ _ __ _ _ _____ ___ _ ")
loggerInit.info("/ -_) _` (_-< || |___| ' \\/ _` | '_ \\ '_/ _ \\ \\ / || |")
loggerInit.info("\\___\\__,_/__/\\_, | |_||_\\__,_| .__/_| \\___/_\\_\\_, |")
loggerInit.info(" |__/ |_| |__/ ")

Functions.log(Functions.INIT_LOG, Functions.INFO, "Release: %s" % (os.getenv("RELEASE_VERSION")))
Functions.log(Functions.INIT_LOG, Functions.DEBUG, 'Environment:')
loggerInit.info("Release: %s" % (os.getenv("RELEASE_VERSION")))
loggerInit.debug('Environment:')
for name, value in os.environ.items():
if "HAPROXY" in name:
Functions.log(Functions.INIT_LOG, Functions.DEBUG, "- {0}: {1}".format(name, value))
loggerInit.debug("- {0}: {1}".format(name, value))

start()

Expand Down
Loading

0 comments on commit 64bc49b

Please sign in to comment.