It's a Python library to parse haproxy config file. Thanks to canopy, which I use for auto-generating Python codes by PEG grammar. But the 'Extension methods for node' feature in canopy seems broken, I always encounter the MRO errors when running parse
function. So I modify the generated codes which mainly rename the TreeNode*
to specified treenode name, eg: GlobalSection, GlobalHeader, BackendHeader, and also complement missing attributes.
This project uses nose for unit testing, but with no more Python libraries dependencies for running.
- Suppose that you have virtualenv installed, if not, please go here to install
- Create a virutalenv and activate it,
$ virtualenv --no-site-packages pyhaproxy
$ source pyhaproxy/bin/activate
- User pip (
pip install pyhaproxy
) or setuptools (easy_install pyhaproxy
) to install it - Install nose dependency for unittest
(pyhaproxy)$ pip install -r requirements.txt
Here is the simple example to show how to use it. See unittest file test.py for more usage details.
#!/usr/bin/env python
# -*- coding: utf8 -*-
from pyhaproxy.parse import Parser
from pyhaproxy.render import Render
import pyhaproxy.config as config
# Build the configuration instance by calling Parser('config_file').build_configuration()
cfg_parser = Parser('haproxy.cfg')
configuration = cfg_parser.build_configuration()
# Get the global section
print configuration.globall # the `global` is keyword of Python, so name it `globall`
print configuration.globall.options() # get the 'option ...' config lines
print configuration.globall.configs() # get config lines except 'option ...' ones
# Get all the frontend sections
frontend_sections = configuration.frontends
# Get frontend sections specifics
for fe_section in frontend_sections:
# Get the name, host, port of the frontend section
print fe_section.name, fe_section.host, fe_section.port
print fe_section.options()
print fe_section.configs()
# Find the frontend by name
the_fe_section = configuration.frontend(the_fe_section_name)
'''To get other sections is ditto.
'''
# Operates the ACL in a frontend, it much likes operating a list
# Get all the ACLs defined in the frontend section
acls = the_fe_section.acls() # return list(config.Acl)
# Find the specified ACL
acl_instance = the_fe_section.acl(the_acl_name) # return config.Acl
# Modify existing ACL
acl_instance.value = 'hdr(host) -i modified.example.com'
# Append the ACL into the frontend section
# for version <= 0.2.4
the_fe_section.acls().append(config.Acl(acl_name, acl_value))
# for version > 0.2.4
the_fe_section.add_acl(config.Acl(acl_name, acl_value))
# Remove ACL
# for version <= 0.2.4
acl_instance = the_fe_section.acl(the_acl_name)
the_fe_section.acls().remove(acl_instance)
# for version > 0.2.4
the_fe_section.remove_acl(the_acl_name)
# Operates the use_backend / default_backend configs in a frontend
# Get all the backend configs
usebackends = the_fe_section.usebackends() # return list(config.UseBackend)
for usebe in usebackends:
# Get the using backend name, operator, condition
print usebe.backend_name, usebe.operator, usebe.backend_condition
# Determine if it's `default_backend` line
print usebe.is_default
# Add a new `use_backend` or `default_backend` line
# for version <= 0.2.4
the_fe_section.usebackends().append(config.UseBackend(backend_name, operator, backend_condition, is_default))
# for version > 0.2.4
the_fe_section.add_usebackend(config.UseBackend(backend_name, operator, backend_condition, is_default))
# Operates the Server in a backend
the_be_section = configuration.backend(the_be_section_name)
# Get all the Server lines in backend section
servers = the_be_section.servers() # return list(config.Server)
# Find the specified Server
the_server = the_be_section.server(the_server_name) # return config.Server
# Get the Server name, host, port
print the_server.name, the_server.host, the_server.port
# Get the Server attributes, for line: `server web_server_1 10.1.1.2:80 cookie 1 check inter 2000 rise 3`
print the_server.attributes # it's is ['cookie', 1, 'check', 'inter', 2000, 'rise', 3]
# Remove the Server by name
# for version <= 0.2.4
the_be_section.servers().remove(the_server)
# for version > 0.2.4
the_be_section.remove_server(server_name)
# Render out to the cfg file
cfg_render = Render(configuration)
cfg_render.dumps_to('./hatest.cfg') # you will see hatest.cfg which is same to the `haproxy.cfg` parsed previously
- Parse
global
section - Parse
frontend
sections - Parse
bind
config lines - Parse
backend
sections - Parse
defaults
sections - Parse
userlist
sections - Parse
listen
sections - Parse
acl
config lines - Parse
use_backend
anddefault_backend
config lines - Render
global
section - Render
frontend
section - Render
backend
sections - Render
defaults
sections - Render
userlist
sections - Render
listen
sections
- Link
backend
withfrontend
byacl
Use nose unit test framework
(pyhaproxy)$ nosetests -sv test.py
- Inspired by @subakva 's haproxy-tools
- Use canopy of @jcoglan for PEG parsing and Python code auto-generating