From 13ab16cd96dda236c9e4c6481e6b09662e8f2179 Mon Sep 17 00:00:00 2001 From: Frank Wall Date: Tue, 5 Dec 2023 23:23:53 +0100 Subject: [PATCH] net/haproxy: replace bundled haproxyctl library The bundled library is a modified version of haproxyctl: https://github.com/neurogeek/haproxyctl Now a proper fork was created: https://github.com/markt-de/haproxy-cli The FreeBSD port is pending approval: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=275562 --- net/haproxy/Makefile | 2 +- net/haproxy/pkg-descr | 3 + .../OPNsense/HAProxy/lib/haproxy/__init__.py | 3 - .../OPNsense/HAProxy/lib/haproxy/cmds.py | 335 ------------------ .../OPNsense/HAProxy/lib/haproxy/conn.py | 83 ----- .../OPNsense/HAProxy/lib/haproxy/const.py | 7 - .../HAProxy/lib/haproxy/tests/__init__.py | 0 .../HAProxy/lib/haproxy/tests/test_cmds.py | 291 --------------- .../HAProxy/lib/haproxy/tests/test_conn.py | 59 --- .../scripts/OPNsense/HAProxy/socketCommand.py | 1 - .../scripts/OPNsense/HAProxy/syncCerts.py | 1 - 11 files changed, 4 insertions(+), 781 deletions(-) delete mode 100755 net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/__init__.py delete mode 100755 net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/cmds.py delete mode 100755 net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/conn.py delete mode 100755 net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/const.py delete mode 100755 net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/tests/__init__.py delete mode 100755 net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/tests/test_cmds.py delete mode 100755 net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/tests/test_conn.py diff --git a/net/haproxy/Makefile b/net/haproxy/Makefile index 49233c6f0..95013f8e1 100644 --- a/net/haproxy/Makefile +++ b/net/haproxy/Makefile @@ -2,7 +2,7 @@ PLUGIN_NAME= haproxy PLUGIN_VERSION= 4.1 PLUGIN_REVISION= 1 PLUGIN_COMMENT= Reliable, high performance TCP/HTTP load balancer -PLUGIN_DEPENDS= haproxy26 +PLUGIN_DEPENDS= haproxy26 py${PLUGIN_PYTHON}-haproxy-cli PLUGIN_MAINTAINER= opnsense@moov.de .include "../../Mk/plugins.mk" diff --git a/net/haproxy/pkg-descr b/net/haproxy/pkg-descr index def41ade0..2681b9f8d 100644 --- a/net/haproxy/pkg-descr +++ b/net/haproxy/pkg-descr @@ -9,6 +9,9 @@ Plugin Changelog Fixed: * fix typo in cert sync script +Changed: +* replace bundled haproxyctl library with haproxy-cli + 4.1 Fixed: diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/__init__.py b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/__init__.py deleted file mode 100755 index c7f37eafa..000000000 --- a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -"""haproxy lib for socket commands. -Based on: https://github.com/neurogeek/haproxyctl""" -__version__ = "1.0" diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/cmds.py b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/cmds.py deleted file mode 100755 index 733daf113..000000000 --- a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/cmds.py +++ /dev/null @@ -1,335 +0,0 @@ -"""cmds.py - Implementations of the different HAProxy commands""" -import re -import csv -import json -from collections import OrderedDict -from io import StringIO - -class Cmd(): - """Cmd - Command base class""" - req_args = [] - args = {} - cmdTxt = "" - helpTxt = "" - - # pylint: disable=unused-argument - def __init__(self, *args, **kwargs): - """Argument to the command are given in kwargs only. We ignore *args.""" - self.args = kwargs - valid_kwargs = [k for (k, v) in kwargs.items() if v is not None] - - if not all([a in valid_kwargs for a in self.req_args]): - raise Exception(f"Wrong number of arguments. Required arguments are: {self.WhatArgs()}") - - def WhatArgs(self): - """Returns a formatted string of arguments to this command.""" - return ",".join(self.req_args) - - @classmethod - def getHelp(cls): - """Get formatted help string for this command.""" - txtArgs = ",".join(cls.req_args) - - if not txtArgs: - txtArgs = "None" - return " ".join((cls.helpTxt, "Arguments: %s" % txtArgs)) - - def getCmd(self): - """Gets the command line for this command. - The default behavior is to apply the args dict to cmdTxt - """ - return self.cmdTxt % self.args - - def getBootstrapOutput(self, resObj): - """ Returns results gathered from HAProxy as jquery bootstrap output """ - args = { - "rows": resObj, - "page": int(self.args['page']) if self.args['page'] != None else 1, - "page_rows": int(self.args['page_rows']) if self.args['page_rows'] != None else len(rows), - "search": self.args['search'], - "sort_col": self.args['sort_col'] if self.args['sort_col'] else 'id', - "sort_dir": self.args['sort_dir'], - } - rows = args['rows'] - # search - if args['search']: - filtered_rows = [] - for row in rows: - def inner(row): - for k, v in row.items(): - if args['search'] in v: - return row - return None - - match = inner(row) - if match: - filtered_rows.append(match) - rows = filtered_rows - - # sort - rows.sort(key=lambda k: k[args['sort_col']], reverse=True if args['sort_dir'] == 'desc' else False) - - # pager - total = len(rows) - pages = [rows[i:i + args['page_rows']] for i in range(0, total, args['page_rows'])] - if pages and (args['page'] > len(pages) or args['page'] < 1): - raise KeyError(f"Current page {args['page']} does not exist. Available pages: {len(pages)}") - page = pages[args['page'] - 1] if pages else [] - - return json.dumps({ - "rows": page, - "total": total, - "rowCount": args['page_rows'], - "current": args['page'] - }) - - def getJsonOutput(self, resObj): - """Returns results gathered from HAProxy as json""" - return json.dumps(resObj) - - def getResult(self, res): - """Returns raw results gathered from HAProxy""" - if res == '\n': - res = None - - if self.args['output'] == 'json': - return self.getJsonOutput(self.getResultObj(res)) - - if self.args['output'] == 'bootstrap': - return self.getBootstrapOutput(self.getResultObj(res)) - - return res - - def getResultObj(self, res): - """Returns refined output from HAProxy, packed inside a Python obj i.e. a dict()""" - return res - -class setServerAgent(Cmd): - cmdTxt = "set server %(backend)s/%(server)s agent %(value)s\r\n" - req_args = ['backend', 'server', 'value'] - helpTxt = "Force a server's agent to a new state." - -class setServerHealth(Cmd): - cmdTxt = "set server %(backend)s/%(server)s health %(value)s\r\n" - req_args = ['backend', 'server', 'value'] - helpTxt = "Force a server's health to a new state." - -class setServerState(Cmd): - cmdTxt = "set server %(backend)s/%(server)s state %(value)s\r\n" - req_args = ['backend', 'server', 'value'] - helpTxt = "Force a server's administrative state to a new state." - -class setServerWeight(Cmd): - cmdTxt = "set server %(backend)s/%(server)s weight %(value)s\r\n" - req_args = ['backend', 'server', 'value'] - helpTxt = "Force a server's weight to a new state." - -class showSslCrtLists(Cmd): - cmdTxt = "show ssl crt-list\r\n" - helpTxt = "Show the list of crt-lists." - - def getResultObj(self, res): - result = { "crt_lists": []} - for line in res.split("\n"): - if line.startswith('/'): - result["crt_lists"].append(line) - return result - -class showSslCrtList(Cmd): - cmdTxt = "show ssl crt-list -n %(crt_list)s\r\n" - req_args = ['crt_list'] - helpTxt = "Show the the content of a crt-list." - - def getResultObj(self, res): - result = {} - list_id = None - for line in res.split("\n"): - if line.startswith('# '): - list_id = line.split("# ")[1] - result["certs"] = [] - - if list_id and line.startswith('/'): - result["certs"].append(line) - - if result: - return result - - return {"error": res.strip()} - -class showSslCerts(Cmd): - cmdTxt = "show ssl cert\r\n" - helpTxt = "Display the SSL certificates used in memory." - - def getResultObj(self, res): - result = { - "transaction": [], - "filename": [] - } - for line in res.split("\n"): - if line.startswith('*'): - result['transaction'].append(line) - elif line.startswith('/'): - result['filename'].append(line) - return result - -class showSslCert(Cmd): - cmdTxt = "show ssl cert %(certfile)s\r\n" - req_args = ['certfile'] - helpTxt = "Display the details of a SSL certificate used in memory." - - def getResultObj(self, res): - result = {} - cert_id = None - for line in res.split("\n"): - if line: - key = line.split(":")[0] - val = line.split(":")[1].strip() - - if key == 'Filename': - cert_id = val - - if cert_id: - result[key] = val - - if result: - return result - - return {"error": res.strip()} - -class addToSslCrtList(Cmd): - cmdTxt = "add ssl crt-list %(crt_list)s %(certfile)s\r\n" - req_args = ['crt_list', 'certfile'] - helpTxt = "Add a ssl cert to a crt-list." - -class delFromSslCrtList(Cmd): - cmdTxt = "del ssl crt-list %(crt_list)s %(certfile)s\r\n" - req_args = ['crt_list', 'certfile'] - helpTxt = "Delete a ssl cert from a crt-list." - -class newSslCrt(Cmd): - """" Create an empty slot for the certificate in HAProxy’s memory """ - cmdTxt = "new ssl cert %(certfile)s\r\n" - req_args = ['certfile'] - helpTxt = "Create a new certificate file to be used in a crt-list or a directory." - -class updateSslCrt(Cmd): - """" Begin a transaction to upload the certificate into a slot in HAProxy’s memory """ - cmdTxt = "set ssl cert %(certfile)s <<\n%(payload)s\r\n" - req_args = ['certfile', 'payload'] - helpTxt = "Replace a certificate file." - -class delSslCrt(Cmd): - """" Begin a transaction to remove the certificate from a slot in HAProxy’s memory """ - cmdTxt = "del ssl cert %(certfile)s\r\n" - req_args = ['certfile'] - helpTxt = "Delete delete an unused certificate file." - -class commitSslCrt(Cmd): - """ Commit the transaction so HAProxy detects the change. """ - cmdTxt = "commit ssl cert %(certfile)s\r\n" - req_args = ['certfile'] - helpTxt = "Commit a certificate file." - -class abortSslCrt(Cmd): - cmdTxt = "abort ssl cert %(certfile)s\r\n" - req_args = ['certfile'] - helpTxt = "Abort a transaction for a certificate file." - -class showFBEnds(Cmd): - """Base class for getting a listing Frontends and Backends""" - switch = "" - cmdTxt = "show stat\r\n" - - def getResult(self, res): - return "\n".join(self._getResult(res)) - - def getResultObj(self, res): - return self._getResult(res) - - def _getResult(self, res): - """Show Frontend/Backends. To do this, we extract info from - the stat command and filter out by a specific - switch (FRONTEND/BACKEND)""" - - if not self.switch: - raise Exception("No action specified") - - result = [] - lines = res.split('\n') - cl = re.compile("^[^,].+," + self.switch.upper() + ",.*$") - - for e in lines: - me = re.match(cl, e) - if me: - print(e) - result.append(e.split(",")[0]) - return result - -class showFrontends(showFBEnds): - """Show frontends command.""" - switch = "frontend" - helpTxt = "List all Frontends." - -class showBackends(showFBEnds): - """Show backends command.""" - switch = "backend" - helpTxt = "List all Backends." - -class showInfo(Cmd): - """Show info HAProxy command""" - cmdTxt = "show info\r\n" - helpTxt = "Show info on HAProxy instance." - - def getResultObj(self, res): - resDict = {} - for line in res.split('\n'): - k, v = line.split(':') - resDict[k] = v - - return resDict - -class showSessions(Cmd): - """Show sess HAProxy command""" - cmdTxt = "show sess\r\n" - helpTxt = "Show HAProxy sessions." - - def getResultObj(self, res): - return res.split('\n') - -class baseStat(Cmd): - """Base class for stats commands.""" - - def getDict(self, res): - # clean response - res = re.sub(r'^# ', '', res, re.MULTILINE) - res = re.sub(r',\n', '\n', res, re.MULTILINE) - res = re.sub(r',\n\n', '\n', res, re.MULTILINE) - - csv_string = StringIO(res) - return csv.DictReader(csv_string, delimiter=',') - -class showServers(baseStat): - """Show all servers. If backend is given, show only servers for this backend. """ - cmdTxt = "show stat\r\n" - helpTxt = "Lists all servers. Filter for servers in backend, if set." - - def getResultObj(self, res): - servers = [] - - reader = self.getDict(res) - for row in reader: - row = OrderedDict(row) - # show only server - if row['svname'] in ['BACKEND', 'FRONTEND']: - continue - - # filter server for given backend - if self.args['backend'] and row['pxname'] != self.args['backend']: - continue - - # add id - row['id'] = f"{row['pxname']}/{row['svname']}" - row.move_to_end('id', last=False) - servers.append(dict(row)) - - return servers diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/conn.py b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/conn.py deleted file mode 100755 index 0c38673c1..000000000 --- a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/conn.py +++ /dev/null @@ -1,83 +0,0 @@ -# pylint: disable=locally-disabled, too-few-public-methods, no-self-use, invalid-name -"""conn.py - Connection module.""" -import re -from socket import socket, AF_INET, AF_UNIX, SOCK_STREAM -from haproxy import const - -class HapError(Exception): - """Generic exception for haproxyctl.""" - pass - -class HaPConn(object): - """HAProxy Socket object. - This class abstract the socket interface so - commands can be sent to HAProxy and results received and - parse by the command objects""" - - def __init__(self, sfile, socket_module=socket): - """Initializes an HAProxy and opens a connection to it - (sfile, type) -> Path for the UNIX socket""" - - self.sock = None - sfile = sfile.strip() - stype = AF_UNIX - self.socket_module = socket_module - - mobj = re.match( - '(?Punix://|tcp://)(?P[^:]+):*(?P[0-9]*)$', sfile) - - if mobj: - proto = mobj.groupdict().get('proto', None) - addr = mobj.groupdict().get('addr', None) - port = mobj.groupdict().get('port', '') - - if not addr or not proto: - raise HapError('Could not determine type of socket.') - - if proto == const.HAP_TCP_PATH: - if not port: - raise HapError('When using a tcp socket, a port is needed.') - stype = AF_INET - sfile = (addr, int(port)) - - if proto == const.HAP_UNIX_PATH: - stype = AF_UNIX - sfile = addr - - # Fallback should be sfile/AF_UNIX by default - self.sfile = (sfile, stype) - self.open() - - def open(self): - """Opens a connection for the socket. - This function should only be called if - self.closed() method was called""" - - sfile, stype = self.sfile - self.sock = self.socket_module(stype, SOCK_STREAM) - self.sock.connect(sfile) - - def sendCmd(self, cmd, objectify=False): - """Receives a command obj and sends it to the socket. Receives the output and passes it - through the command to parse it. - objectify -> Return an object instead of plain text""" - - res = "" - try: - self.sock.send(cmd.getCmd()) - except TypeError: - self.sock.send(bytearray(cmd.getCmd(), 'ASCII')) - output = self.sock.recv(const.HAP_BUFSIZE) - - while output: - res += output.decode('UTF-8') - output = self.sock.recv(const.HAP_BUFSIZE) - - if objectify: - return cmd.getResultObj(res) - - return cmd.getResult(res) - - def close(self): - """Closes the socket""" - self.sock.close() diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/const.py b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/const.py deleted file mode 100755 index ebd60d8c8..000000000 --- a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/const.py +++ /dev/null @@ -1,7 +0,0 @@ -"""const.py - Constants for haproxyctl.""" -HAP_OK = 1 -HAP_ERR = 2 -HAP_SOCK_ERR = 3 -HAP_BUFSIZE = 8192 -HAP_UNIX_PATH = 'unix://' -HAP_TCP_PATH = 'tcp://' diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/tests/__init__.py b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/tests/__init__.py deleted file mode 100755 index e69de29bb..000000000 diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/tests/test_cmds.py b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/tests/test_cmds.py deleted file mode 100755 index 327787163..000000000 --- a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/tests/test_cmds.py +++ /dev/null @@ -1,291 +0,0 @@ -# pylint: disable=star-args, locally-disabled, too-few-public-methods, no-self-use, invalid-name -"""test_cmds.py - Unittests related to command implementations.""" -import sys, os, unittest - -sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) -from haproxy import cmds - - -class TestCommands(unittest.TestCase): - """Tests all of the commands.""" - - def setUp(self): - self.maxDiff = None - self.pem_cert_content = """ - -----BEGIN CERTIFICATE----- - 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 - +VCAIWMkC36Dvg== - -----END CERTIFICATE----- - - -----BEGIN RSA PRIVATE KEY----- - MIIJKgIBAAKCAgEAvsNKU59F2gpl1fzbk7hD64Q3zk1hH9Im1IsN9ppF5tqdsPPG - n3Q8QgcKpnJ/SrtnPl4Xqp3bJyV20lJWTxuVU7ImM8g4tStQB4XojTtv8A4E7/wN - T0beUBFI5CQ+YLzRqEYBbcXV5pxx/TyqdxYIbEopeZ4v2ZsCwDiTr7qkirxhEGow - ITZuRFD+xwBrykvuazmFx441Z+qMcLXbMinJq++d81VnrPtCXAcSHdFqOTUhocvI - Tv736hDfNeoW0zqwG9eW9WHCyLOCQfdmh03zXJy8eg/UxaocYdfSSVERD2pGse5K - 6oeyMkdfyC1uojZn0NU5RQS6dsiQiZPCpiN7m2nuDhFAlSAB2xq7I3TY1N15R5yL - 4kO8DcUcmkC0Du0Nch41zI+NGGjXuLhVQhxhqy7kkMXSJI8NP9KvG3oSwOe0MUNy - jUdcywWpSExtjb6BRYLc/Sf3xVZI74EK0B0Vtzj43dAQzxGdAojzpYdH++dUOiKA - 6EAu6ldrpzOMsYyNpIsMjSfInkzzWvxm4Fla7ZDodOKQ2ahaXfDrH71a9jpNB306 - kKNBS7XdQxUByjwIYQ6PRmqGEtNxxfx3E8r/TVtcy0VGK8l97q8wv47Q3nglsjlx - peZoR1wS5rMBUla3Vk8YVMyOLD87RLodvRVgkpeqMmz233k7kykv1bhi8bECAwEA - AQKCAgEAswbSPXJPetahRdcdNyAKVgBq4ykJinSOTpAF1bZo/cOTlFrjwAe0+X5k - R1tTDQ6dURG7AjtNTgrB3Za6O1m2paqeYaB5X8U7QSQx4EG0xsRRa+vPjeQDhX8D - OmCtTdpGpLa2Zo/xM5EFBVUm4cYCt6ZOED4dyAnK5hzytUvjWfR6343Yh4LurxyY - TqidgGgMZALDA0n54wFjNe/lu8kt5Ddns9MmDlhrqbRVEzjSiMfNPWvjHAf7IGcf - JBkBvNDqL+b/XGCYDgUxrLkDNt44E2VhGOi8lZkVM9n5FyeGbEIgAKKTGlGpMbh8 - MoA4wPFwMrO5IIXUfN+zjfnnBkZsnAomGQYDh/hrsQPwU7MoyfO0Wzw+RzLWK8JH - EnjR7O/Lgh+A2AdLhCLiRC5td2uuJ2yLRIRUlcQPsCsYnCCL6Ip9IwK1idmQySGw - bG83decXNSJUv5h3qF6f3fl+JPrHnAbviBzEJ67xAf1MdHbFxwYvRFVfEHj9RZ3W - z+cw7ofD8XVHTfXn0XipvYqI/bVsitMXI35pOt+/ZV8rjJlXopw+IV6U9/60cBkk - BXC7ONDyH2pNwxPbRgcLm2sEK0L9qhxRzCj0iD1WyOAiFJX4ytVbJhR7pt0goiun - i2XDh2l8hoK1lKZNS/yJ+VhnbX595mdqScmIXD8utlgK8f0bLfECggEBAORXimSK - gzegnsBjieTtzC6MmRRxxN46vnMZ2LCeLMxhs3vM7LBcBfsQYqbt/FVFtYBRpr+d - TGTmfPXqKuSqbtAbghxAMo/lECXzALa0nQSsz1fFhX8B7slFarsDmmCb1GmXF/kG - ku/Uoa7jmY3htBj5rjVHjDKPZFVetU+2wbuwlU17Bj4nlSzqud4NMlu56pm3FZ/1 - BAhMxm3z6dLnOgqJzpN1QmKZHNkjLmi8fza/HQM5pP3DpQcPiyuLzywGIqHaO1qT - OIdpZfLEvNpMV7bJ2bagv5nX3TVRWWsBkh0HCAuH30qqaVPpQvkPem1zsM3x+D5q - +PhMIPGpbQiUyCUCggEBANXefd0ZcJymG15WJyO44eFwzgMz9ezfdB8INa+vCOiZ - Y7FtYDgEKu4uzBxtMjO4mQO6DCkfi7JwTJFN4ag3dJEJNGmrf7Xe84IAImJQk0Of - BojAXCFAuNf1Xl3prkvnvtzNirwQMHCUbv5wYzOqglgj2i/hjIj3/Wbt91riq5j+ - 4qQT4kkw/XgCtbQ27HohKIcC/mXbHchEi7NtXrGoM1xqmu1mGH1uul3LQ6p5VwHc - ZFiIAC0awsx9Qe9khZ5EGpZuS0tqJsREcv8ygYMvWcPJEv8aMQM7Nj4biA5rKEgo - L+66ibpntldvbz2qntEvJ2rKzGci0RDUQHy4sW8/d50CggEBAKCZaX7ZZPzk/YL2 - /2+CSQ+cV7ZnZj2fN4Ag96UROxTsyp4SPY60yogQuDIMRGN9SfDcfNlcOvTkn5Me - hdiafqHkFxjjlixawYbPaPsYAS/ek156UDBKHbZ2GmE6YYP9VeKGIJhHpWUFOkqV - TdTaoB7IzVwv3E1bSQg6Om+8bHoj8n6yPmvMz0DuPpgM1BRrqLNAb/c3DwT/ari+ - ywBJHSt4TVCtMmnCouWdtvB3U0ogFLnF+2N4DUPwDMQt6yJdllIb+Y706NdkrA2Z - jfJDq5WmVnf6i4gaqTzs4GVAj5HW9jOV9ti/DqGz+CTQXB1LN1lCDIVqG34XnTwb - G9LjQfkCggEAZwYAt4tTtgJGWNFDlW+wT/sZIm3bX7ncpD4+Ll0w+2s4nPXFTfaj - /4zHgkIP1t5rx2HODdlGYDS8jZpow7HDE0LN3sFgienWf5808QtDhWWLrkCLoPEe - mdl3FeJFtgby6EaTODjMPM8kEKlvACp5E6BhsIMEQc7EYNrtNvjOFKtj3go+DWfu - EeusQB3dGI/0h+UnS0WcOSbb7RkYbphJ9ZDdBNMTpQi7+ga6l9pP0XOrWwJYo2Gq - yPrl0j4oJ69C54hF+RQvjIg0pT5dKSacJTYtUnn5dkcFwDFe/yMbinbhcCynwAXJ - zqC9g4U3cCk44bbDdENPVr4IOox13NND+QKCAQEAilm2oMZoP3WGkBMTSzJl6OGd - F8NnE95noleknNFYuThhCT6T4Z1s28VpxXV7d0DTNOtXj+TzeZq4jrwkgOSZbif0 - 8ky4gRZmm0iFwvAu8ZXk1olHbhMZnCOfh0Qhd4bU2tSoWgWVIAQWEHUhDI7Q1rsX - s4sCjYHKuNMEKdfYvxtKeiunoFqdmT65hwM9o3TfvJfm/RChb7i/nVruXQ6IhPEM - 9WYZS7hlKyqVBESJuonR15biy7Xov5ELl6A821cskZO3vTwtlBSeCDiqaeVLpKR3 - aYwf5YZo7v+N8KBSLEdLNjoKK4PfXUdczD7uOUllbd4/MRgCn4EmFvmpljGiEQ== - -----END RSA PRIVATE KEY----- - - -----BEGIN CERTIFICATE----- - MIIEqzCCApOgAwIBAgIRAIvhKg5ZRO08VGQx8JdhT+UwDQYJKoZIhvcNAQELBQAw - GjEYMBYGA1UEAwwPRmFrZSBMRSBSb290IFgxMB4XDTE2MDUyMzIyMDc1OVoXDTM2 - MDUyMzIyMDc1OVowIjEgMB4GA1UEAwwXRmFrZSBMRSBJbnRlcm1lZGlhdGUgWDEw - ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtWKySDn7rWZc5ggjz3ZB0 - 8jO4xti3uzINfD5sQ7Lj7hzetUT+wQob+iXSZkhnvx+IvdbXF5/yt8aWPpUKnPym - oLxsYiI5gQBLxNDzIec0OIaflWqAr29m7J8+NNtApEN8nZFnf3bhehZW7AxmS1m0 - ZnSsdHw0Fw+bgixPg2MQ9k9oefFeqa+7Kqdlz5bbrUYV2volxhDFtnI4Mh8BiWCN - xDH1Hizq+GKCcHsinDZWurCqder/afJBnQs+SBSL6MVApHt+d35zjBD92fO2Je56 - dhMfzCgOKXeJ340WhW3TjD1zqLZXeaCyUNRnfOmWZV8nEhtHOFbUCU7r/KkjMZO9 - AgMBAAGjgeMwgeAwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw - HQYDVR0OBBYEFMDMA0a5WCDMXHJw8+EuyyCm9Wg6MHoGCCsGAQUFBwEBBG4wbDA0 - BggrBgEFBQcwAYYoaHR0cDovL29jc3Auc3RnLXJvb3QteDEubGV0c2VuY3J5cHQu - b3JnLzA0BggrBgEFBQcwAoYoaHR0cDovL2NlcnQuc3RnLXJvb3QteDEubGV0c2Vu - Y3J5cHQub3JnLzAfBgNVHSMEGDAWgBTBJnSkikSg5vogKNhcI5pFiBh54DANBgkq - hkiG9w0BAQsFAAOCAgEABYSu4Il+fI0MYU42OTmEj+1HqQ5DvyAeyCA6sGuZdwjF - UGeVOv3NnLyfofuUOjEbY5irFCDtnv+0ckukUZN9lz4Q2YjWGUpW4TTu3ieTsaC9 - AFvCSgNHJyWSVtWvB5XDxsqawl1KzHzzwr132bF2rtGtazSqVqK9E07sGHMCf+zp - DQVDVVGtqZPHwX3KqUtefE621b8RI6VCl4oD30Olf8pjuzG4JKBFRFclzLRjo/h7 - IkkfjZ8wDa7faOjVXx6n+eUQ29cIMCzr8/rNWHS9pYGGQKJiY2xmVC9h12H99Xyf - zWE9vb5zKP3MVG6neX1hSdo7PEAb9fqRhHkqVsqUvJlIRmvXvVKTwNCP3eCjRCCI - PTAvjV+4ni786iXwwFYNz8l3PmPLCyQXWGohnJ8iBm+5nk7O2ynaPVW0U2W+pt2w - SVuvdDM5zGv2f9ltNWUiYZHJ1mmO97jSY/6YfdOUH66iRtQtDkHBRdkNBsMbD+Em - 2TgBldtHNSJBfB3pm9FblgOcJ0FSWcUDWJ7vO0+NTXlgrRofRT6pVywzxVo6dND0 - WzYlTWeUVsO40xJqhgUQRER9YLOLxJ0O6C8i0xFxAMKOtSdodMB3RIwt7RFQ0uyt - n5Z5MqkYhlMI3J1tPRTp1nEt9fyGspBOO05gi148Qasp+3N+svqKomoQglNoAxU= - -----END CERTIFICATE----- - """ - - self.Resp = { - "disable": "disable server redis-ro/redis-ro0", - "set-server-agent": "set server redis-ro/redis-ro0 agent up", - "set-server-health": "set server redis-ro/redis-ro0 health stopping", - "set-server-state": "set server redis-ro/redis-ro0 state drain", - "set-server-weight": "set server redis-ro/redis-ro0 weight 10", - "frontends": "show stat", - "info": "show info", - "sessions": "show sess", - "servers": "show stat", - "show-ssl-crt-lists": "show ssl crt-list", - "show-ssl-crt-list": "show ssl crt-list -n /tmp/haproxy/ssl/601a7392cc9984.99301413.certlist", - "show-ssl-certs": "show ssl cert", - "show-ssl-cert": "show ssl cert /tmp/haproxy/ssl/601a70e4844b0.pem", - "add-to-crt-list": "add ssl crt-list /tmp/haproxy/ssl/601a7392cc9984.99301413.certlist /tmp/haproxy/ssl/601a70e4844b0.pem", - "del-from-crt-list": "del ssl crt-list /tmp/haproxy/ssl/601a7392cc9984.99301413.certlist /tmp/haproxy/ssl/601a70e4844b0.pem", - "new-ssl-cert": "new ssl cert /tmp/haproxy/ssl/601a70e4844b0.pem", - "update-ssl-cert": "set ssl cert /tmp/haproxy/ssl/601a70e4844b0.pem <<\n%s" % self.pem_cert_content, - "del-ssl-cert": "del ssl cert /tmp/haproxy/ssl/601a70e4844b0.pem", - "commit-ssl-cert": "commit ssl cert /tmp/haproxy/ssl/601a70e4844b0.pem", - "abort-ssl-cert": "abort ssl cert /tmp/haproxy/ssl/601a70e4844b0.pem", - } - - self.Resp = dict([(k, v + "\r\n") for k, v in self.Resp.items()]) - - def test_setServerAgent(self): - """Test 'set server agent' command""" - args = {"backend": "redis-ro", "server": "redis-ro0", "value": "up"} - cmdOutput = cmds.setServerAgent(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["set-server-agent"]) - - def test_setServerHealth(self): - """Test 'set server health' command""" - args = {"backend": "redis-ro", "server": "redis-ro0", "value": "stopping"} - cmdOutput = cmds.setServerHealth(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["set-server-health"]) - - def test_setServerState(self): - """Test 'set server state' command""" - args = {"backend": "redis-ro", "server": "redis-ro0", "value": "drain"} - cmdOutput = cmds.setServerState(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["set-server-state"]) - - def test_setServerWeight(self): - """Test 'set server weight' command""" - args = {"backend": "redis-ro", "server": "redis-ro0", "value": "10"} - cmdOutput = cmds.setServerWeight(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["set-server-weight"]) - - def test_showFrontends(self): - """Test 'frontends/backends' commands""" - args = {} - cmdOutput = cmds.showFrontends(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["frontends"]) - - def test_showInfo(self): - """Test 'show info' command""" - cmdOutput = cmds.showInfo().getCmd() - self.assertEqual(cmdOutput, self.Resp["info"]) - - def test_showSessions(self): - """Test 'show sess' command""" - cmdOutput = cmds.showSessions().getCmd() - self.assertEqual(cmdOutput, self.Resp["sessions"]) - - def test_showServers(self): - """Test 'show stat' command""" - args = {"backend": "redis-ro"} - cmdOutput = cmds.showServers(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["servers"]) - - def test_showSslCrtLists(self): - """Test 'show ssl crt-list' command""" - cmdOutput = cmds.showSslCrtLists().getCmd() - self.assertEqual(cmdOutput, self.Resp["show-ssl-crt-lists"]) - - def test_showSslCrtList(self): - """Test 'show ssl crt-list ' command""" - args = { - "crt_list": "/tmp/haproxy/ssl/601a7392cc9984.99301413.certlist", - } - cmdOutput = cmds.showSslCrtList(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["show-ssl-crt-list"]) - - def test_showSslCerts(self): - """Test 'show ssl cert' command""" - cmdOutput = cmds.showSslCerts().getCmd() - self.assertEqual(cmdOutput, self.Resp["show-ssl-certs"]) - - def test_showSslCert(self): - """Test 'show ssl cert ' command""" - args = { - "certfile": "/tmp/haproxy/ssl/601a70e4844b0.pem" - } - cmdOutput = cmds.showSslCert(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["show-ssl-cert"]) - - def test_addToSslCrtList(self): - """Test 'add ssl crt-list ' command""" - args = { - "crt_list": "/tmp/haproxy/ssl/601a7392cc9984.99301413.certlist", - "certfile": "/tmp/haproxy/ssl/601a70e4844b0.pem" - } - cmdOutput = cmds.addToSslCrtList(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["add-to-crt-list"]) - - def test_delFromSslCrtList(self): - """Test 'del ssl crt-list ' command""" - args = { - "crt_list": "/tmp/haproxy/ssl/601a7392cc9984.99301413.certlist", - "certfile": "/tmp/haproxy/ssl/601a70e4844b0.pem" - } - cmdOutput = cmds.delFromSslCrtList(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["del-from-crt-list"]) - - def test_newSslCrt(self): - """Test 'new ssl cert ' command""" - args = { - "certfile": "/tmp/haproxy/ssl/601a70e4844b0.pem", - } - cmdOutput = cmds.newSslCrt(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["new-ssl-cert"]) - - def test_updateSslCrt(self): - """Test 'set ssl cert ' command""" - args = { - "certfile": "/tmp/haproxy/ssl/601a70e4844b0.pem", - "payload": "%s" % self.pem_cert_content - } - cmdOutput = cmds.updateSslCrt(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["update-ssl-cert"]) - - def test_delSslCrt(self): - """Test 'del ssl cert ' command""" - args = { - "certfile": "/tmp/haproxy/ssl/601a70e4844b0.pem", - } - cmdOutput = cmds.delSslCrt(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["del-ssl-cert"]) - - def test_commitSslCrt(self): - """Test 'commit ssl cert ' command""" - args = { - "certfile": "/tmp/haproxy/ssl/601a70e4844b0.pem", - } - cmdOutput = cmds.commitSslCrt(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["commit-ssl-cert"]) - - def test_abortSslCrt(self): - """Test 'abort ssl cert ' command""" - args = { - "certfile": "/tmp/haproxy/ssl/601a70e4844b0.pem", - } - cmdOutput = cmds.abortSslCrt(**args).getCmd() - self.assertEqual(cmdOutput, self.Resp["abort-ssl-cert"]) - - -if __name__ == '__main__': - unittest.main() diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/tests/test_conn.py b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/tests/test_conn.py deleted file mode 100755 index ea8c15f60..000000000 --- a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/lib/haproxy/tests/test_conn.py +++ /dev/null @@ -1,59 +0,0 @@ -# pylint: disable=locally-disabled, too-few-public-methods, no-self-use, invalid-name, broad-except -"""test_conn.py - Unittests related to connections to HAProxy.""" -import sys, os -sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) -from haproxy import conn -import unittest -from socket import AF_INET, AF_UNIX - -class SimpleConnMock(object): - """Simple socket mock.""" - def __init__(self, stype, stream): - self.stype = stype - self.stream = stream - - def connect(self, addr): - """Mocked socket.connect method.""" - pass - -class TestConnection(unittest.TestCase): - """Tests different aspects of haproxyctl's connections to HAProxy.""" - - def testConnSimple(self): - """Tests that connection to non-protocol path works and fallsback to UNIX socket.""" - sfile = "/some/path/to/socket.sock" - c = conn.HaPConn(sfile, socket_module=SimpleConnMock) - addr, stype = c.sfile - self.assertEqual(sfile, addr) - self.assertEqual(stype, AF_UNIX) - - def testConnUnixString(self): - """Tests that unix:// protocol works and connects to a socket.""" - sfile = "unix:///some/path/to/socket.socket" - c = conn.HaPConn(sfile, socket_module=SimpleConnMock) - addr, stype = c.sfile - self.assertEqual("/some/path/to/socket.socket", addr) - self.assertEqual(stype, AF_UNIX) - - def testConnTCPString(self): - """Tests that tcp:// protocol works and connects to an IP.""" - sfile = "tcp://1.2.3.4:8080" - c = conn.HaPConn(sfile, socket_module=SimpleConnMock) - addr, stype = c.sfile - ip, port = addr - self.assertEqual("1.2.3.4", ip) - self.assertEqual(8080, port) - self.assertEqual(stype, AF_INET) - - def testConnTCPStringNoPort(self): - """Tests that passing a tcp:// address with no port, raises an Exception.""" - sfile = "tcp://1.2.3.4" - # Not using assertRaises because we still support 2.6 - try: - conn.HaPConn(sfile, socket_module=SimpleConnMock) - raise Exception('Connection should have thrown an exception') - except conn.HapError: - pass - -if __name__ == '__main__': - unittest.main() diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/socketCommand.py b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/socketCommand.py index 554db684a..bcf407c36 100755 --- a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/socketCommand.py +++ b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/socketCommand.py @@ -4,7 +4,6 @@ import sys import argparse import traceback -sys.path.append(os.path.join(os.path.dirname(__file__), 'lib')) from haproxy.conn import HaPConn from haproxy import cmds diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/syncCerts.py b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/syncCerts.py index f4932a0cd..8df8543f3 100755 --- a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/syncCerts.py +++ b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/syncCerts.py @@ -9,7 +9,6 @@ import OpenSSL import json from typing import List -sys.path.append(os.path.join(os.path.dirname(__file__), 'lib')) from haproxy.conn import HaPConn from haproxy import cmds