Desenvolvendo uma Plataforma de Gerenciamento HAProxy

  1. Entrodução =============

Este artigo apresenta um script desenvolvido em Python para gerenciar configurações do HAProxy em sistemas Linux. A ferramenta permite consultar, adicionar e remover nós de backend de forma interativa.

  1. Pré-requisitos =================

O script foi testado exclusivamente em sistemas operacionais Linux. Para utilizá-lo, é necessário criar um arquivo de configuração chamado haproxy no meesmo diretório onde o script será executado.

  1. Estrutura do Arquivo de Configuração =======================================

O arquivo haproxy deve conter a configuração base do HAProxy. A seguir, apresenta-se um exemplo de configruação:


global
    log 127.0.0.1 local2
    daemon
    maxconn 256
    log 127.0.0.1 local2 info

defaults
    log global
    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms
    option dontlognull

listen stats :8888
    stats enable
    stats uri /admin
    stats auth admin:1234

frontend oldboy.org
    bind 0.0.0.0:80
    option httplog
    option httpclose
    option forwardfor
    log global
    acl www hdr_reg(host) -i www.oldboy.org
    use_backend www.oldboy.org if www

backend www.oldboy.org
    server srv001 100.1.7.9 weight 20 maxconn 3000
    server srv002 100.1.7.9 weight 20 maxconn 3000
    server srv003 100.1.7.9 weight 20 maxconn 3000
  1. Script de Gerenciamento ==========================

A seguir, apresenta-se o código Python para a plataforma de gerenciamento:


#!/usr/bin/env python
# -*- coding:utf-8 -*-

import os
import sys

ARQUIVO_CONFIG = "haproxy"
ARQUIVO_TEMP = "temp_config"

def exibir_cabecalho():
    print "\033[32;1m*********** Plataforma de Gerenciamento HAProxy ***********\033[0m"

def listar_backend(nome_backend):
    try:
        with open(ARQUIVO_CONFIG, 'r') as f:
            linhas = [linha.strip() for linha in f.readlines()]
        
        indice = linhas.index("backend " + nome_backend) + 1
        
        print "\033[32;1mLista de Servidores do Backend\033[0m".center(60, "*")
        for linha in linhas[indice:]:
            print linha
        print "\033[32;1mFim da Lista\033[0m".center(50, "*")
        
        return True
    except ValueError:
        print "\033[31;1mErro: Backend não encontrado!\033[0m"
        return False

def adicionar_no(dados):
    try:
        registro = dados["record"]
        
        chaves = []
        valores = []
        
        for chave in registro:
            chaves.append(chave)
            valores.append(registro[chave])
        
        chaves.insert(2, valores[2])
        chaves.insert(1, str(valores[1]))
        chaves.insert(0, str(valores[0]))
        chaves.reverse()
        
        nova_linha = ' '.join(chaves) + "\n"
        
        print "*********** \033[32;1mNovo Nós Adicionado\033[0m ***********"
        print nova_linha
        print "********************  Fim  *************************"
        
        with open(ARQUIVO_CONFIG, 'r') as origem:
            with open(ARQUIVO_TEMP, 'a+') as destino:
                for linha in origem:
                    destino.write(linha)
                destino.write(nova_linha)
        
        os.remove(ARQUIVO_CONFIG)
        os.rename(ARQUIVO_TEMP, ARQUIVO_CONFIG)
        
        return True
    except Exception as e:
        print "\031[31;1mErro ao adicionar nó: %s\033[0m" % str(e)
        return False

def remover_no(indice):
    try:
        with open(ARQUIVO_CONFIG, 'r') as f:
            linhas = [linha.strip() for linha in f.readlines()]
        
        indice_backend = linhas.index("backend www.oldboy.org") + 1
        
        # Mapeia o índice do usuário para o índice real no arquivo
        linha_remover = indice_backend - 1 + indice
        
        with open(ARQUIVO_CONFIG, 'w') as f:
            for i, linha in enumerate(linhas):
                if i != linha_remover:
                    f.write(linha + "\n")
        
        print "*********** \033[32;1mNó removido com sucesso\033[0m ***********"
        return True
    except Exception as e:
        print "\033[31;1mErro ao remover nó: %s\033[0m" % str(e)
        return False

def menu_consulta():
    while True:
        entrada = raw_input("\033[32;1mDigite o nome do backend para consulta:  b para voltar:  q para sair\033[0m ")
        
        if entrada == "b":
            break
        elif entrada == "q":
            print "\033[32;1m******** Obrigado por usar o sistema. Até mais! *********\033[0m"
            exit()
        elif entrada == "www.oldboy.org":
            listar_backend(entrada)
            
            opcao = raw_input("Digite b para voltar:  q para sair do programa: ")
            if opcao == "b":
                continue
            elif opcao == "q":
                print "\033[32;1m******** Obrigado por usar o sistema. Até mais! *********\033[0m"
                exit()
        else:
            print "\033[31;1mEntrada inválida. Backend não encontrado. Por favor, tente novamente.\033[0m"

def menu_adicao():
    dados = raw_input("Digite os dados do nó a ser adicionado: ").strip()
    no_adicionar = eval(dados)
    adicionar_no(no_adicionar)

def menu_remocao():
    try:
        with open(ARQUIVO_CONFIG, 'r') as f:
            linhas = [linha.strip() for linha in f.readlines()]
        
        indice_backend = linhas.index("backend www.oldboy.org") + 1
        
        print "\nNos disponíveis para remoção:"
        contador = 1
        for linha in linhas[indice_backend:]:
            print "%d - %s" % (contador, linha)
            contador += 1
        
        entrada = raw_input("Digite o número do nó a ser removido: ")
        numero = int(entrada)
        
        if numero >= 1 and numero < contador:
            remover_no(numero)
        else:
            print "\033[31;1mNúmero inválido!\033[0m"
    except ValueError as e:
        print "\033[31;1mErro: valor digitado inválido\033[0m"
    except Exception as e:
        print "\033[31;1mErro ao processar remoção: %s\033[0m" % str(e)

def menu_principal():
    while True:
        exibir_cabecalho()
        opcao = raw_input("\033[32;1ma - Consultar nós    b - Adicionar nó    c - Remover nó    q - Sair\033[0m ")
        
        if opcao == "a":
            menu_consulta()
        elif opcao == "b":
            menu_adicao()
        elif opcao == "c":
            menu_remocao()
        elif opcao == "q":
            print "\033[32;1m******** Obrigado por usar o sistema. Até mais! *********\033[0m"
            exit()
        else:
            print "\033[31;1mOpção inválida. Por favor, tente novamente.\033[0m"

if __name__ == "__main__":
    menu_principal()
  1. Utilização do Sistema ========================

O sistema apresenta um menu interativo com as seguintes opções:

  • Opção a: Permite consultar os nós de um backend específico
  • Opção b: Possibilita adicionar novos nós ao backend
  • Opção c: Permite remover nós existentes
  • Opção q: Encerra o programa
  1. Exemplo de Adição de Nó ==========================

Para adicionar um novo nó, utilize o seguinte formato quando solicitado:


{'record': {'nome': 'servidor_novo', 'ip': '100.1.7.10', 'peso': '20', 'maxconn': '3000'}}

O código processará o dicionário e adicionará o novo servidor ao arquivo de configuração do HAProxy.

Tags: Python haproxy load-balancer Linux gerenciamento

Publicado em 7-25 20:12