Source code for src.core.haproxyupdater.haproxyupdate

.. module:: haproxyupdate
   :synopsis: Module for updating haproxy


import os
from .confighandler import ConfigHandler
from .runtimeupdater import RuntimeUpdater
from .haproxyreloader import HaproxyReloader

[docs]class HaproxyUpdate(object): """ Class for handling haproxy update and reload This class contains handlers which controls haproxy uptation and reload. Haproxy can be updated wither by updating its config file followed by a reload via systemd or via binary. The other way to reload haproxy is via the exposed socket. This type of update does not require any reload For updating via runtime haproxy needs to maintain a pool if inactive backends. When a new live backend comes, we can pull an inactive live backend and make it live changing its ip to that of the live backend Args: **kwargs (dictionary) : params in key/value dict format """ def __init__(self, **kwargs): """ Init method for the class Extracts the desired params and stores them as instance variables Also it sanitisez the params Args: **kwargs (dictionary) : params in key/value dict format """ # Extract the desired params self.haproxy_config_file = kwargs.get("haproxy_config_file") self.template_file = kwargs.get("template_file") self.backend_port = int(kwargs.get("backend_port")) self.node_list = kwargs.get("node_list") self.haproxy_binary = kwargs.get("haproxy_binary") self.start_by = kwargs.get("start_by") self.haproxy_socket_file = kwargs.get("haproxy_socket_file") self.pid_file = kwargs.get("pid_file") self.backend_name = kwargs.get("backend_name") self.update_type = kwargs.get("update_type") self.node_slots = int(kwargs.get("node_slots")) self.service_name = kwargs.get("service_name") self.backend_maxconn = kwargs.get("backend_maxconn") self.check_interval = kwargs.get("check_interval") self.logger = kwargs.get("logger") """ Valid methods to start haproxy. .. note:: init methods is not supported yet. """ self.valid_start_by = [ "binary", "systemd", "init" ] """ Valid methods to update haproxy """ self.valid_update_types = [ "update_by_config", "update_by_runtime" ] def __sanitise(self): """ Method to for performing sanity checks on the params This method will check that the params received are inline with what we desire. Returns: bool : Result of sanity check """ if not os.path.isfile(self.haproxy_config_file): return False if not os.path.isfile(self.template_file): return False if self.backend_port < 0 or self.backend_port > 65536: return False if not self.backend_name: return False if self.node_slots and self.node_slots <= 0: return False if not self.update_type: return False if self.update_type not in self.valid_update_types: return False if not self.node_slots: return False if self.node_slots <=0: return False if not self.node_list: return False if not self.haproxy_socket_file: return False for sock_file in self.haproxy_socket_file.split(","): if not os.path.exists(sock_file.strip()): return False if self.update_type == "update_by_config": if not self.start_by: return False if not self.start_by in self.valid_start_by: return False if self.start_by == "systemd": if not self.service_name: return False if self.start_by == "binary": if not self.haproxy_binary: return False if not os.path.isfile(self.haproxy_binary): return False if not self.pid_file: return False if not os.path.isfile(self.pid_file): return False return True
[docs] def update_node_list(self, node_list): """Method to update active node list This method will e called to update the list of active backends. Haproxy needs to be updated and optionally reloaded if this list changes Args: node_list (list) : List containing IPs/Hostnames of active backends """ self.node_list = node_list
[docs] def update_haproxy(self): """ Updates haproxy config This method updates haproxy config with the help of the util methods. Returns: bool : Wether haproxy was updated successfully or not. """ if not self.__sanitise(): return False if self.update_type == "update_by_runtime": updated = self.__update_haproxy_by_runtime() else: updated = self.update_haproxy_by_config_reload() return updated
[docs] def update_haproxy_by_config_reload(self, update_only=False): """ Method to update haproxy via config reload This method will update haproxy via updating its config and subsequently reloading it. The actual update will be done by the confighandler module and reload will be done by haproxyreloader. Optinaly is **upate_only** is set to True then only config will be updated and reload will not be done. Args: update_only (bool) : Whether only update is required or both update and reload is required. Returns: bool : Whether successfully updated/reloaded as the case may be """ if self.update_type == "update_by_config": """ If update is to be done via config updation, then total number of backend node slots will be set to the number of active backends found. This because, for update via config we do not require any pool of inactive nodes. So number of slots will be and should be equal to number of active backends. """ self.node_slots = len(self.node_list) # update haproxy updated = ConfigHandler.update_config(haproxy_config_file=self.haproxy_config_file, template_file=self.template_file, node_list=self.node_list, backend_port=self.backend_port, node_slots=self.node_slots, backend_maxconn=self.backend_maxconn, check_interval=self.check_interval, logger=self.logger ) if update_only: # if it was update only, the return return updated # Reload haproxy reloaded = HaproxyReloader.reload_haproxy(start_by=self.start_by, haproxy_config_file=self.haproxy_config_file, service_name=self.service_name, haproxy_binary=self.haproxy_binary, pid_file=self.pid_file, haproxy_socket_file=self.haproxy_socket_file, logger=self.logger ) return reloaded
def __update_haproxy_by_runtime(self): """ Method to update haproxy via runtime change over unix socket This method updates haproxy via runtime using runtimeupdater module. Once it is updated over the socket, the changes takes place almost instantly without any need to reload. Once updating is done, the config file is also updated so that the runtime config and the actual config on disk stays consistent. Like this, even if we have to restart haproxy for some reason, it will start back with its proper configuration and not stale configuration. Returns: bool : Successfully updated or not """ updated, stats = RuntimeUpdater.update_haproxy_runtime(node_ips=self.node_list, port=self.backend_port, sock_file=self.haproxy_socket_file, node_name=self.backend_name, logger=self.logger) if not updated: return False # Update the config after updating haproxy updated = ConfigHandler.update_config(haproxy_config_file=self.haproxy_config_file, template_file=self.template_file, node_list=self.node_list, backend_maxconn=self.backend_maxconn, check_interval=self.check_interval, backend_port=self.backend_port, inactive_nodes_count=stats.get("inactive_nodes_count"), logger=self.logger) if not updated: ''' Log error, runtime updation succeeded but config file could not be updated ''' return True
if __name__ == "__main__": hup = HaproxyUpdate( haproxy_config_file="/etc/haproxy/haproxy.cfg", template_file="/home/deep/elasticpyproxy/etc/haproxy.cofig.template", backend_port=6003, node_list=[""], haproxy_binary="/usr/sbin/haproxy", start_by="binary", haproxy_socket_file="/var/run/haproxy/haproxy.sock", backend_name="haproxynode", service_name="haproxy", node_slots=6, pid_file="/run/", update_type="update_by_config" ) res = hup.update_haproxy() print (res)