From 88813efbc934b1c5b7d07b7fbcce5e0afd81b9d1 Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Wed, 6 Nov 2024 13:53:25 +0100 Subject: [PATCH] Adding lib/pp_admintools/app/haproxy.py --- lib/pp_admintools/app/haproxy.py | 168 +++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 lib/pp_admintools/app/haproxy.py diff --git a/lib/pp_admintools/app/haproxy.py b/lib/pp_admintools/app/haproxy.py new file mode 100644 index 0000000..8bf864d --- /dev/null +++ b/lib/pp_admintools/app/haproxy.py @@ -0,0 +1,168 @@ +# -*- coding: utf-8 -*- +""" +@summary: A base module for th application class of the hap-admin application. + +@author: Frank Brehm +@contact: frank.brehm@pixelpark.com +@copyright: © 2024 by Frank Brehm, Berlin +""" +from __future__ import absolute_import + +# Standard modules +import logging +import re + +# Third party modules +from fb_tools.socket_obj.tcp import TcpSocket +from fb_tools.socket_obj.unix import UnixSocket + +from pathlib import Path + +# Own modules +from . import BaseDPXApplication +from .. import __version__ as GLOBAL_VERSION +from .. import pp +from ..common import split_parts +from ..errors import DpxAppError +from ..xlate import XLATOR + +__version__ = '0.1.0' +LOG = logging.getLogger(__name__) + +_ = XLATOR.gettext +ngettext = XLATOR.ngettext + + +# ============================================================================= +class HapAdminError(DpxAppError): + """Base exception class for all exceptions in this module.""" + pass + + +# ============================================================================= +class HapConfigFileError(HapAdminError): + """Base exception class for all exceptions relating to the HAProxy configuration.""" + pass + + +# ============================================================================= +class HapAdminApplication(BaseDPXApplication): + """Application class for the hap-admin tool.""" + + default_config_file = Path('/etc/haproxy/haproxy.cfg') + + valid_sections = ( + 'global', 'defaults', 'frontend', 'backend', 'listen', 'userlist', + 'peers', 'mailers', 'program', 'http-errors', 'ring', 'log-forward', 'cache', + ) + + re_comment = re.compile(r'\s*#.*') + + # ------------------------------------------------------------------------- + def __init__(self, config_file=None, *args, **kwargs): + """Initialise the current application object.""" + self._config_file = self.default_config_file + + self.stats_sockets = { + 'user': [], + 'operator': [], + 'admin': [], + } + + super(HapAdminApplication, self).__init__(*args, **kwargs) + + if config_file: + self.config_file = config_file + + # ----------------------------------------------------------- + @property + def config_file(self): + """Return the path of the HAProxy configuration file.""" + return self._config_file + + @config_file.setter + def config_file(self, value): + if value is None: + self._config_file = self.default_config_file + return + + path = Path(value) + if not path.is_absolute(): + msg = _('The HAProxy configuration filename {!r} must be an absolute filename.') + raise HapConfigFileError(msg.format(str(path))) + + self._config_file = path + + # ------------------------------------------------------------------------- + def as_dict(self, short=True): + """ + Transform the elements of the object into a dict. + + @param short: don't include local properties in resulting dict. + @type short: bool + + @return: structure as dict + @rtype: dict + """ + res = super(HapAdminApplication, self).as_dict(short=short) + + res['config_file'] = str(self.config_file) + + res['stats_sockets'] = {} + + for level in ('user', 'operator', 'admin'): + res['stats_sockets'][level] = [] + for sock in self.stats_sockets[level]: + res['stats_sockets'][level].append(sock.as_dict(short=short)) + + return res + + # ------------------------------------------------------------------------- + def read_hap_config(self): + """Read the HAProxy configuration file.""" + LOG.debug(_('Reading the HAProxy configuration file {!r} ...').format(str(self.config_file))) + + content = self.read_file(self.config_file, quiet=True) + + current_section = None + + for line in content.splitlines(): + _line = line.strip() + if not line: + continue + + _line = self.re_comment('', _line) + if not line: + continue + + parts = split_parts(_line) + + if parts[0] in self.valid_sections: + current_section = _line + if self.verbose > 0: + LOG.debug(f'New section: {current_section}') + continue + + if current_section == 'global': + if parts[0].lower() == 'stats': + if len(parts) > 2 and parts[1].lower() == 'socket': + self._add_socket(parts[2:]) + + # # ------------------------------------------------------------------------- + # def _add_socket(self, parts): + + # i = 0 + # for part in parts: + # if i == 0: + + + + +# ============================================================================= + +if __name__ == '__main__': + + pass + + +# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 list -- 2.39.5