Source code for saltext.haproxy.modules.haproxyconn

"""
Support for haproxy

.. versionadded:: 2014.7.0
"""

import logging
import os
import stat
import time

try:
    import haproxy.cmds  # pylint: disable=no-name-in-module
    import haproxy.conn  # pylint: disable=no-name-in-module

    HAS_HAPROXY = True
except ImportError:
    HAS_HAPROXY = False

log = logging.getLogger(__name__)

__virtualname__ = "haproxy"

# Default socket location
DEFAULT_SOCKET_URL = "/var/run/haproxy.sock"

# Numeric fields returned by stats
FIELD_NUMERIC = ["weight", "bin", "bout"]
# Field specifying the actual server name
FIELD_NODE_NAME = "name"


[docs] def __virtual__(): """ Only load the module if haproxyctl is installed """ if HAS_HAPROXY: return __virtualname__ return ( False, "The haproxyconn execution module cannot be loaded: haproxyctl module not available", )
def _get_conn(socket=DEFAULT_SOCKET_URL): """ Get connection to haproxy socket. """ assert os.path.exists(socket), f"{socket} does not exist." issock = os.stat(socket).st_mode assert stat.S_ISSOCK(issock), f"{socket} is not a socket." ha_conn = haproxy.conn.HaPConn(socket) return ha_conn
[docs] def list_servers(backend, socket=DEFAULT_SOCKET_URL, objectify=False): """ List servers in haproxy backend. backend haproxy backend socket haproxy stats socket, default ``/var/run/haproxy.sock`` CLI Example: .. code-block:: bash salt '*' haproxy.list_servers mysql """ ha_conn = _get_conn(socket) ha_cmd = haproxy.cmds.listServers(backend=backend) return ha_conn.sendCmd(ha_cmd, objectify=objectify)
[docs] def wait_state(backend, server, value="up", timeout=60 * 5, socket=DEFAULT_SOCKET_URL): """ Wait for a specific server state backend haproxy backend server targeted server value state value timeout timeout before giving up state value, default 5 min socket haproxy stats socket, default ``/var/run/haproxy.sock`` CLI Example: .. code-block:: bash salt '*' haproxy.wait_state mysql server01 up 60 """ t = time.time() + timeout while time.time() < t: if get_backend(backend=backend, socket=socket)[server]["status"].lower() == value.lower(): return True return False
[docs] def get_backend(backend, socket=DEFAULT_SOCKET_URL): """ Receive information about a specific backend. backend haproxy backend socket haproxy stats socket, default ``/var/run/haproxy.sock`` CLI Example: .. code-block:: bash salt '*' haproxy.get_backend mysql """ backend_data = list_servers(backend=backend, socket=socket).replace("\n", " ").split(" ") result = {} # Convert given string to Integer def num(s): try: return int(s) except ValueError: return s active_field = "" for data in backend_data: # Check if field or server name if ":" in data: active_field = data.replace(":", "").lower() continue if active_field.lower() == FIELD_NODE_NAME: active_server = data result[active_server] = {} continue # Format and set returned field data to active server if active_field in FIELD_NUMERIC: if data == "": result[active_server][active_field] = 0 else: result[active_server][active_field] = num(data) else: result[active_server][active_field] = data return result
[docs] def enable_server(name, backend, socket=DEFAULT_SOCKET_URL): """ Enable Server in haproxy name Server to enable backend haproxy backend, or all backends if "*" is supplied socket haproxy stats socket, default ``/var/run/haproxy.sock`` CLI Example: .. code-block:: bash salt '*' haproxy.enable_server web1.example.com www """ if backend == "*": backends = show_backends(socket=socket).split("\n") else: backends = [backend] results = {} for backend in backends: ha_conn = _get_conn(socket) ha_cmd = haproxy.cmds.enableServer(server=name, backend=backend) ha_conn.sendCmd(ha_cmd) results[backend] = list_servers(backend, socket=socket) return results
[docs] def disable_server(name, backend, socket=DEFAULT_SOCKET_URL): """ Disable server in haproxy. name Server to disable backend haproxy backend, or all backends if "*" is supplied socket haproxy stats socket, default ``/var/run/haproxy.sock`` CLI Example: .. code-block:: bash salt '*' haproxy.disable_server db1.example.com mysql """ if backend == "*": backends = show_backends(socket=socket).split("\n") else: backends = [backend] results = {} for backend in backends: ha_conn = _get_conn(socket) ha_cmd = haproxy.cmds.disableServer(server=name, backend=backend) ha_conn.sendCmd(ha_cmd) results[backend] = list_servers(backend, socket=socket) return results
[docs] def get_weight(name, backend, socket=DEFAULT_SOCKET_URL): """ Get server weight name Server name backend haproxy backend socket haproxy stats socket, default ``/var/run/haproxy.sock`` CLI Example: .. code-block:: bash salt '*' haproxy.get_weight web1.example.com www """ ha_conn = _get_conn(socket) ha_cmd = haproxy.cmds.getWeight(server=name, backend=backend) return ha_conn.sendCmd(ha_cmd)
[docs] def set_weight(name, backend, weight=0, socket=DEFAULT_SOCKET_URL): """ Set server weight name Server name backend haproxy backend weight Server Weight socket haproxy stats socket, default ``/var/run/haproxy.sock`` CLI Example: .. code-block:: bash salt '*' haproxy.set_weight web1.example.com www 13 """ ha_conn = _get_conn(socket) ha_cmd = haproxy.cmds.getWeight(server=name, backend=backend, weight=weight) ha_conn.sendCmd(ha_cmd) return get_weight(name, backend, socket=socket)
[docs] def set_state(name, backend, state, socket=DEFAULT_SOCKET_URL): """ Force a server's administrative state to a new state. This can be useful to disable load balancing and/or any traffic to a server. Setting the state to "ready" puts the server in normal mode, and the command is the equivalent of the "enable server" command. Setting the state to "maint" disables any traffic to the server as well as any health checks. This is the equivalent of the "disable server" command. Setting the mode to "drain" only removes the server from load balancing but still allows it to be checked and to accept new persistent connections. Changes are propagated to tracking servers if any. name Server name backend haproxy backend state A string of the state to set. Must be 'ready', 'drain', or 'maint' socket haproxy stats socket, default ``/var/run/haproxy.sock`` CLI Example: .. code-block:: bash salt '*' haproxy.set_state my_proxy_server my_backend ready """ # Pulling this in from the latest 0.5 release which is not yet in PyPi. # https://github.com/neurogeek/haproxyctl # pylint: disable=invalid-name class setServerState(haproxy.cmds.Cmd): """Set server state command.""" cmdTxt = "set server %(backend)s/%(server)s state %(value)s\r\n" p_args = ["backend", "server", "value"] helpTxt = "Force a server's administrative state to a new state." ha_conn = _get_conn(socket) ha_cmd = setServerState(server=name, backend=backend, value=state) return ha_conn.sendCmd(ha_cmd)
[docs] def show_frontends(socket=DEFAULT_SOCKET_URL): """ Show HaProxy frontends socket haproxy stats socket, default ``/var/run/haproxy.sock`` CLI Example: .. code-block:: bash salt '*' haproxy.show_frontends """ ha_conn = _get_conn(socket) ha_cmd = haproxy.cmds.showFrontends() return ha_conn.sendCmd(ha_cmd)
[docs] def list_frontends(socket=DEFAULT_SOCKET_URL): """ List HaProxy frontends socket haproxy stats socket, default ``/var/run/haproxy.sock`` CLI Example: .. code-block:: bash salt '*' haproxy.list_frontends """ return show_frontends(socket=socket).split("\n")
[docs] def show_backends(socket=DEFAULT_SOCKET_URL): """ Show HaProxy Backends socket haproxy stats socket, default ``/var/run/haproxy.sock`` CLI Example: .. code-block:: bash salt '*' haproxy.show_backends """ ha_conn = _get_conn(socket) ha_cmd = haproxy.cmds.showBackends() return ha_conn.sendCmd(ha_cmd)
[docs] def list_backends(servers=True, socket=DEFAULT_SOCKET_URL): """ List HaProxy Backends socket haproxy stats socket, default ``/var/run/haproxy.sock`` servers list backends with servers CLI Example: .. code-block:: bash salt '*' haproxy.list_backends """ if not servers: return show_backends(socket=socket).split("\n") else: result = {} for backend in list_backends(servers=False, socket=socket): result[backend] = get_backend(backend=backend, socket=socket) return result
[docs] def get_sessions(name, backend, socket=DEFAULT_SOCKET_URL): """ .. versionadded:: 2016.11.0 Get number of current sessions on server in backend (scur) name Server name backend haproxy backend socket haproxy stats socket, default ``/var/run/haproxy.sock`` CLI Example: .. code-block:: bash salt '*' haproxy.get_sessions web1.example.com www """ # pylint: disable=invalid-name class getStats(haproxy.cmds.Cmd): p_args = ["backend", "server"] cmdTxt = "show stat\r\n" helpText = "Fetch all statistics" ha_conn = _get_conn(socket) ha_cmd = getStats(server=name, backend=backend) result = ha_conn.sendCmd(ha_cmd) for line in result.split("\n"): if line.startswith(backend): out_cols = line.split(",") if out_cols[1] == name: return out_cols[4]