-
Notifications
You must be signed in to change notification settings - Fork 97
Flexible configuration syntax #107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
benwebber
wants to merge
17
commits into
master
Choose a base branch
from
refactor/simplify
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+689
−1,091
Open
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
f97acc0
Support free-form configuration syntax
benwebber b9600d4
Replace templates with single file
benwebber 2ed2936
Handle boolean switches
benwebber 11b7a5d
Test defaults/global section expansion
benwebber 9464978
Test expansion of all non-proxy sections
benwebber 3ea637a
Test proxy configuration expansion
benwebber 085c3b7
Test boolean expansion
benwebber e332a0e
Update default configuration with new syntax
benwebber e03f67d
Configure tox
benwebber 6e45276
Sort options deterministically
benwebber 85f00d0
Configure Travis CI
benwebber 4cf51fa
Omit options using false values
benwebber bd23485
Document new configuration syntax
benwebber 1456c0e
Sort section instances by name
benwebber ac29865
Install tox-travis locally
benwebber 3ef2eb9
Fix Travis CI configuration
benwebber 2d287f1
Update integration test configuration
benwebber File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,8 @@ | ||
*.egg-info/ | ||
*.py[co] | ||
*.swp | ||
.cache/ | ||
.coverage | ||
.kitchen | ||
.tox/ | ||
__pycache__/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
sudo: false | ||
language: python | ||
python: | ||
- '2.7' | ||
- '3.5' | ||
- '3.6' | ||
install: pip install tox-travis | ||
script: tox |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
from __future__ import unicode_literals | ||
|
||
import collections | ||
import sys | ||
|
||
|
||
if sys.version_info.major < 3: | ||
string_types = basestring | ||
else: | ||
string_types = str | ||
|
||
|
||
# Certain options need to precede others in the configuration file. Options with | ||
# larger weights sink to the bottom. | ||
# Weights taken from Puppetlabs HAProxy module: | ||
# <https://github.com/puppetlabs/puppetlabs-haproxy/blob/093b9ec1c56551a9e9679dbb3eeef87da851737e/templates/fragments/_options.erb> | ||
OPTION_WEIGHTS = { | ||
'acl': -1, | ||
'tcp-request': 2, | ||
'block': 3, | ||
'http-request': 4, | ||
'reqallow': 5, | ||
'reqdel': 5, | ||
'reqdeny': 5, | ||
'reqidel': 5, | ||
'reqideny': 5, | ||
'reqipass': 5, | ||
'reqirep': 5, | ||
'reqitarpit': 5, | ||
'reqpass': 5, | ||
'reqrep': 5, | ||
'reqtarpit': 5, | ||
'reqadd': 6, | ||
'redirect': 7, | ||
'use_backend': 8, | ||
'use-server': 9, | ||
'server': 100, | ||
} | ||
|
||
|
||
def sort_by_weight(mapping, weights=None): | ||
""" | ||
Sort mapping keys first by weight, then alphabetically. | ||
""" | ||
if weights: | ||
key = lambda kv: (weights.get(kv[0], 0), kv[0]) | ||
else: | ||
key = None | ||
return collections.OrderedDict(sorted(mapping.items(), key=key)) | ||
|
||
|
||
def expand(options): | ||
""" | ||
Expand a nested configuration dictionary. | ||
""" | ||
for key, value in sort_by_weight(options, weights=OPTION_WEIGHTS).items(): | ||
if not isinstance(value, collections.Container) or isinstance(value, string_types): | ||
yield (key, value) | ||
continue | ||
elif isinstance(value, collections.Sequence): | ||
for item in value: | ||
yield (key, item) | ||
continue | ||
elif isinstance(value, collections.Mapping): | ||
yield (key, list(expand((value)))) | ||
continue | ||
yield (key, value) | ||
|
||
|
||
def to_haproxy(options): | ||
""" | ||
Yield HAProxy configuration lines from a nested configuration dictionary. | ||
""" | ||
options = expand(options) | ||
for key, value in options: | ||
if value is True: | ||
yield str(key) | ||
elif value is False: | ||
continue | ||
elif isinstance(value, collections.Sequence) and not isinstance(value, string_types): | ||
for sub_key, sub_value in value: | ||
yield '{} {} {}'.format(key, sub_key, sub_value) | ||
else: | ||
yield '{} {}'.format(key, value) | ||
|
||
|
||
class FilterModule(object): | ||
def filters(self): | ||
return { | ||
'to_haproxy': to_haproxy, | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from setuptools import ( | ||
find_packages, | ||
setup, | ||
) | ||
|
||
|
||
setup( | ||
name='ansible-haproxy', | ||
packages=find_packages(), | ||
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,199 +1,7 @@ | ||
--- | ||
|
||
## ASSEMBLE CONFIG - RESOLVERS | ||
|
||
- name: 'Create directory for the resolvers' | ||
file: | ||
path: "{{ haproxy_config_dir }}/resolvers.d" | ||
state: directory | ||
|
||
- name: "List files for the resolvers" | ||
find: | ||
paths: "{{ haproxy_config_dir }}/resolvers.d" | ||
patterns: "*.cfg" | ||
register: directory_contents | ||
changed_when: false | ||
|
||
- name: "Remove unmanaged files for the resolvers" | ||
file: | ||
path: "{{ item.path }}" | ||
state: absent | ||
when: (item.path | basename) not in (haproxy_resolvers | json_query('[*].name') | map('regex_replace', '(.*)', '\\1.cfg') | list) | ||
with_items: "{{ directory_contents.files }}" | ||
|
||
- name: 'Build up the resolvers' | ||
- name: Configure HAProxy | ||
template: | ||
src: "resolvers.cfg" | ||
dest: "{{ haproxy_config_dir }}/resolvers.d/{{ item.name }}.cfg" | ||
with_items: "{{ haproxy_resolvers }}" | ||
when: haproxy_resolvers is defined | ||
|
||
## ASSEMBLE CONFIG - FRONTEND | ||
|
||
- name: 'Create directory for the frontend' | ||
file: | ||
path: "{{ haproxy_config_dir }}/frontends.d" | ||
state: directory | ||
|
||
- name: "List files for the frontends" | ||
find: | ||
paths: "{{ haproxy_config_dir }}/frontends.d" | ||
patterns: "*.cfg" | ||
register: directory_contents | ||
changed_when: false | ||
|
||
- name: "Remove unmanaged files for the frontends" | ||
file: | ||
path: "{{ item.path }}" | ||
state: absent | ||
when: (item.path | basename) not in (haproxy_frontends | json_query('[*].name') | map('regex_replace', '(.*)', '\\1.cfg') | list) | ||
with_items: "{{ directory_contents.files }}" | ||
|
||
- name: 'Build up the frontends' | ||
template: | ||
src: "frontend.cfg" | ||
dest: "{{ haproxy_config_dir }}/frontends.d/{{ item.name }}.cfg" | ||
with_items: "{{ haproxy_frontends }}" | ||
when: haproxy_frontends is defined | ||
|
||
## ASSEMBLE CONFIG - BACKEND | ||
|
||
- name: 'Create directory for the backends' | ||
file: | ||
path: "{{ haproxy_config_dir }}/backends.d" | ||
state: directory | ||
|
||
- name: "List files for the backends" | ||
find: | ||
paths: "{{ haproxy_config_dir }}/backends.d" | ||
patterns: "*.cfg" | ||
register: directory_contents | ||
changed_when: false | ||
|
||
- name: "Remove unmanaged files for the backends" | ||
file: | ||
path: "{{ item.path }}" | ||
state: absent | ||
when: (item.path | basename) not in (haproxy_backends | json_query('[*].name') | map('regex_replace', '(.*)', '\\1.cfg') | list) | ||
with_items: "{{ directory_contents.files }}" | ||
|
||
- name: 'Build up the backends' | ||
template: | ||
src: "backend.cfg" | ||
dest: "{{ haproxy_config_dir }}/backends.d/{{ item.name }}.cfg" | ||
with_items: "{{ haproxy_backends }}" | ||
when: haproxy_backends is defined | ||
|
||
## ASSEMBLE CONFIG - LISTEN | ||
|
||
- name: 'Create directory for the listen sections' | ||
file: | ||
path: "{{ haproxy_config_dir }}/listen.d" | ||
state: directory | ||
|
||
- name: "List files the listen sections" | ||
find: | ||
paths: "{{ haproxy_config_dir }}/listen.d" | ||
patterns: "*.cfg" | ||
register: directory_contents | ||
changed_when: false | ||
|
||
- name: "Remove unmanaged files the listen sections" | ||
file: | ||
path: "{{ item.path }}" | ||
state: absent | ||
when: (item.path | basename) not in (haproxy_listen | json_query('[*].name') | map('regex_replace', '(.*)', '\\1.cfg') | list) | ||
with_items: "{{ directory_contents.files }}" | ||
|
||
- name: 'Build up the listen sections' | ||
template: | ||
src: "listen.cfg" | ||
dest: "{{ haproxy_config_dir }}/listen.d/{{ item.name }}.cfg" | ||
with_items: "{{ haproxy_listen }}" | ||
when: haproxy_listen is defined | ||
|
||
## ASSEMBLE CONFIG - USERLIST | ||
|
||
- name: 'Create directory for the userlists' | ||
file: path={{ haproxy_config_dir }}/userlists.d state=directory | ||
|
||
- name: "List files for the userlists" | ||
find: | ||
paths: "{{ haproxy_config_dir }}/userlists.d" | ||
patterns: "*.cfg" | ||
register: directory_contents | ||
changed_when: false | ||
|
||
- name: "Remove unmanaged files for the userlists" | ||
file: | ||
path: "{{ item.path }}" | ||
state: absent | ||
when: (item.path | basename) not in (haproxy_userlists | json_query('[*].name') | map('regex_replace', '(.*)', '\\1.cfg') | list) | ||
with_items: "{{ directory_contents.files }}" | ||
|
||
- name: 'Build up the userlist sections' | ||
template: | ||
src: userlist.cfg | ||
dest: "{{ haproxy_config_dir }}/userlists.d/{{ item.name }}.cfg" | ||
with_items: "{{ haproxy_userlists }}" | ||
when: haproxy_userlists is defined | ||
|
||
## ASSEMBLE CONFIG - GLOBAL & DEFAULT | ||
|
||
- name: 'Delete the compiled folder' | ||
file: | ||
path: "{{ haproxy_config_dir }}/compiled" | ||
state: absent | ||
|
||
- name: 'Create the compiled folder' | ||
file: | ||
path: "{{ haproxy_config_dir }}/compiled" | ||
state: directory | ||
|
||
- name: 'Build up the global config' | ||
template: | ||
src: "global.cfg" | ||
dest: "{{ haproxy_config_dir }}/compiled/01-global.cfg" | ||
when: haproxy_global is defined | ||
tags: 'test' | ||
|
||
- name: 'Build up the default config' | ||
template: | ||
src: "defaults.cfg" | ||
dest: "{{ haproxy_config_dir }}/compiled/02-defaults.cfg" | ||
when: haproxy_defaults is defined | ||
|
||
## ASSEMBLE FINAL CONFIG | ||
|
||
- name: 'Assemble the resolvers sections configuration file' | ||
assemble: | ||
src: "{{ haproxy_config_dir }}/resolvers.d" | ||
dest: "{{ haproxy_config_dir }}/compiled/03-resolvers.cfg" | ||
|
||
- name: 'Assemble the backends configuration file' | ||
assemble: | ||
src: "{{ haproxy_config_dir }}/backends.d" | ||
dest: "{{ haproxy_config_dir }}/compiled/04-backends.cfg" | ||
|
||
- name: 'Assemble the frontends configuration file' | ||
assemble: | ||
src: "{{ haproxy_config_dir }}/frontends.d" | ||
dest: "{{ haproxy_config_dir }}/compiled/05-frontends.cfg" | ||
|
||
- name: 'Assemble the listen sections configuration file' | ||
assemble: | ||
src: "{{ haproxy_config_dir }}/listen.d" | ||
dest: "{{ haproxy_config_dir }}/compiled/06-listen.cfg" | ||
|
||
- name: 'Assemble the userlists sections configuration file' | ||
assemble: | ||
src: "{{ haproxy_config_dir }}/userlists.d" | ||
dest: "{{ haproxy_config_dir }}/compiled/07-userlists.cfg" | ||
|
||
- name: 'Assemble the final configuration file' | ||
assemble: | ||
src: "{{ haproxy_config_dir }}/compiled" | ||
src: haproxy.cfg.j2 | ||
dest: "{{ haproxy_config_file }}" | ||
backup: yes | ||
validate: "haproxy -c -f %s" | ||
validate: haproxy -c -f %s | ||
notify: restart haproxy |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,17 @@ | ||
{%- macro http_response(responses = []) -%} | ||
{%- for response in responses -%} | ||
http-response {{ response.action }}{% if response.param is defined %} {{ response.param }}{% endif %}{% if response.condition is defined %} {{ response.condition }}{% endif %} | ||
{% macro section(section, instances, single=False) %} | ||
{% if instances is defined %} | ||
{% if single %} | ||
{{ section }} | ||
{{ instances|to_haproxy|join('\n')|indent(indentfirst=True) }} | ||
|
||
{% endfor -%} | ||
{%- endmacro -%} | ||
|
||
{%- macro http_request(requests = []) -%} | ||
{%- for request in requests -%} | ||
http-request {{ request.action }}{% if request.param is defined %} {{ request.param }}{% endif %}{% if request.condition is defined %} {{ request.condition }}{% endif %} | ||
{% else %} | ||
{% for name, options in (instances|dictsort(case_sensitive=True)).items() %} | ||
{{ section }} {{ name }} | ||
{{ options|to_haproxy|join('\n')|indent(indentfirst=True) }} | ||
|
||
{% endfor -%} | ||
{%- endmacro -%} | ||
{% endfor %} | ||
|
||
{% endif %} | ||
{% endif %} | ||
{% endmacro %} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{%- import '_macros.j2' as macros with context -%} | ||
# {{ ansible_managed }} | ||
|
||
|
||
{{ macros.section('global', haproxy_global, single=True) -}} | ||
{{- macros.section('defaults', haproxy_defaults, single=True) -}} | ||
{{- macros.section('peers', haproxy_peers) -}} | ||
{{- macros.section('resolvers', haproxy_resolvers) -}} | ||
{{- macros.section('mailers', haproxy_mailers) -}} | ||
{{- macros.section('userlist', haproxy_userlists) -}} | ||
{{- macros.section('frontend', haproxy_frontends) -}} | ||
{{- macros.section('backend', haproxy_backends) -}} | ||
{{- macros.section('listen', haproxy_listens) -}} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import os | ||
import sys | ||
|
||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
--- | ||
haproxy_defaults: | ||
log: global | ||
mode: http | ||
option: | ||
- httplog | ||
- dontlognull | ||
timeout: | ||
connect: 5000 | ||
client: 50000 | ||
server: 50000 | ||
errorfile: | ||
400: /etc/haproxy/errors/400.http | ||
403: /etc/haproxy/errors/403.http | ||
408: /etc/haproxy/errors/408.http | ||
500: /etc/haproxy/errors/500.http | ||
502: /etc/haproxy/errors/502.http | ||
503: /etc/haproxy/errors/503.http | ||
504: /etc/haproxy/errors/504.http | ||
|
||
|
||
haproxy_global: | ||
log: | ||
/dev/log: | ||
- local0 | ||
- local1 notice | ||
chroot: /var/lib/haproxy | ||
stats: | ||
socket: /run/haproxy/admin.sock mode 660 level admin | ||
timeout: 30s | ||
user: haproxy | ||
group: haproxy | ||
daemon: true | ||
ca-base: /etc/ssl/certs | ||
crt-base: /etc/ssl/private | ||
ssl-default-bind-ciphers: ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS | ||
ssl-default-bind-options: no-sslv3 | ||
|
||
|
||
haproxy_mailers: | ||
mailers1: | ||
mailer: | ||
smtp1: 192.0.2.1:587 | ||
smtp2: 192.0.2.2:587 | ||
mailers2: | ||
mailer: | ||
smtp1: 192.51.100.1:587 | ||
smtp2: 192.51.100.2:587 | ||
|
||
|
||
haproxy_peers: | ||
peers1: | ||
peer: | ||
haproxy1: 192.0.2.1:1024 | ||
haproxy2: 192.0.2.2:1024 | ||
haproxy3: 192.0.2.3:1024 | ||
peers2: | ||
peer: | ||
haproxy1: 192.51.100.1:1024 | ||
haproxy2: 192.51.100.2:1024 | ||
haproxy3: 192.51.100.3:1024 | ||
|
||
|
||
haproxy_resolvers: | ||
resolvers1: | ||
nameserver: | ||
dns1: 192.0.2.1:53 | ||
dns2: 192.0.2.2:53 | ||
resolve_retries: 3 | ||
timeout: | ||
retry: 1s | ||
hold: | ||
valid: 10s | ||
resolvers2: | ||
nameserver: | ||
dns1: 192.51.100.1:53 | ||
dns2: 192.51.100.2:53 | ||
resolve_retries: 3 | ||
timeout: | ||
retry: 1s | ||
hold: | ||
valid: 10s | ||
|
||
|
||
haproxy_userlists: | ||
userlist1: | ||
group: | ||
- G1 users tiger,scott | ||
- G2 users xdb,scott | ||
user: | ||
- tiger password $6$k6y3o.eP$JlKBx9za9667qe4(...)xHSwRv6J.C0/D7cV91 | ||
- scott insecure-password elgato | ||
- xdb insecure-password hello | ||
userlist2: | ||
group: | ||
- G1 | ||
- G2 | ||
user: | ||
- tiger password $6$k6y3o.eP$JlKBx(...)xHSwRv6J.C0/D7cV91 groups G1 | ||
- scott insecure-password elgato groups G1,G2 | ||
- xdb insecure-password hello groups G2 | ||
|
||
|
||
haproxy_listens: | ||
listen1: | ||
mode: http | ||
bind: | ||
- :80 | ||
- :443 ssl crt /etc/haproxy/site.pem | ||
acl: | ||
- invalid_src src 0.0.0.0/7 224.0.0.0/3 | ||
- invalid_src src_port 0:1023 | ||
- local_dst hdr(host) -i localhost | ||
- es req.fhdr(accept-language),language(es;fr;en) -m str es | ||
- fr req.fhdr(accept-language),language(es;fr;en) -m str fr | ||
- en req.fhdr(accept-language),language(es;fr;en) -m str en | ||
tcp-request: | ||
connection: | ||
- accept if { src -f /etc/haproxy/whitelist.lst } | ||
- reject if { src_conn_rate gt 10 } | ||
- track-sc0 src | ||
block: | ||
- if invalid_src || local_dst | ||
http-request: | ||
deny: | ||
- if invalid_src || local_dst | ||
reqdel: | ||
- ^X-Forwarded-For:.* | ||
- ^Cookie:.*SERVER= | ||
reqpass: | ||
- ^Host:\ www.private\.local | ||
reqadd: | ||
- X-Proto:\ SSL if is-ssl | ||
redirect: | ||
- prefix https://mysite.com set-cookie SEEN=1 if !cookie_set | ||
- prefix https://mysite.com if login_page !secure | ||
- prefix http://mysite.com drop-query if login_page !uid_given | ||
- location http://mysite.com/ if !login_page secure | ||
- location / clear-cookie USERID= if logout | ||
use_backend: | ||
- backend1 if is-app1 | ||
- backend2 if is-app2 | ||
use-server: | ||
- www if { req_ssl_sni -i www.example.com } | ||
- mail if { req_ssl_sni -i mail.example.com } | ||
- imap if { req_ssl_sni -i imap.example.com } | ||
server: | ||
www: 192.0.2.1:443 weight 0 | ||
mail: 192.0.2.1:587 weight 0 | ||
imap: 192.0.2.1:993 weight 0 | ||
default: 192.0.2.2:443 check | ||
listen2: | ||
no log: true | ||
disabled: false |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
--- | ||
haproxy_defaults: | ||
- errorfile 400 /etc/haproxy/errors/400.http | ||
- errorfile 403 /etc/haproxy/errors/403.http | ||
- errorfile 408 /etc/haproxy/errors/408.http | ||
- errorfile 500 /etc/haproxy/errors/500.http | ||
- errorfile 502 /etc/haproxy/errors/502.http | ||
- errorfile 503 /etc/haproxy/errors/503.http | ||
- errorfile 504 /etc/haproxy/errors/504.http | ||
- log global | ||
- mode http | ||
# Preserve order within YAML sequences. | ||
- option httplog | ||
- option dontlognull | ||
- timeout client 50000 | ||
- timeout connect 5000 | ||
- timeout server 50000 | ||
|
||
haproxy_global: | ||
- ca-base /etc/ssl/certs | ||
- chroot /var/lib/haproxy | ||
- crt-base /etc/ssl/private | ||
- daemon | ||
- group haproxy | ||
- log /dev/log local0 | ||
- log /dev/log local1 notice | ||
- ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS | ||
- ssl-default-bind-options no-sslv3 | ||
- stats socket /run/haproxy/admin.sock mode 660 level admin | ||
- stats timeout 30s | ||
- user haproxy | ||
|
||
haproxy_mailers: | ||
mailers1: | ||
- mailer smtp1 192.0.2.1:587 | ||
- mailer smtp2 192.0.2.2:587 | ||
mailers2: | ||
- mailer smtp1 192.51.100.1:587 | ||
- mailer smtp2 192.51.100.2:587 | ||
|
||
haproxy_peers: | ||
peers1: | ||
- peer haproxy1 192.0.2.1:1024 | ||
- peer haproxy2 192.0.2.2:1024 | ||
- peer haproxy3 192.0.2.3:1024 | ||
peers2: | ||
- peer haproxy1 192.51.100.1:1024 | ||
- peer haproxy2 192.51.100.2:1024 | ||
- peer haproxy3 192.51.100.3:1024 | ||
|
||
haproxy_resolvers: | ||
resolvers1: | ||
- hold valid 10s | ||
- nameserver dns1 192.0.2.1:53 | ||
- nameserver dns2 192.0.2.2:53 | ||
- resolve_retries 3 | ||
- timeout retry 1s | ||
resolvers2: | ||
- hold valid 10s | ||
- nameserver dns1 192.51.100.1:53 | ||
- nameserver dns2 192.51.100.2:53 | ||
- resolve_retries 3 | ||
- timeout retry 1s | ||
|
||
haproxy_userlists: | ||
userlist1: | ||
- group G1 users tiger,scott | ||
- group G2 users xdb,scott | ||
- user tiger password $6$k6y3o.eP$JlKBx9za9667qe4(...)xHSwRv6J.C0/D7cV91 | ||
- user scott insecure-password elgato | ||
- user xdb insecure-password hello | ||
userlist2: | ||
- group G1 | ||
- group G2 | ||
- user tiger password $6$k6y3o.eP$JlKBx(...)xHSwRv6J.C0/D7cV91 groups G1 | ||
- user scott insecure-password elgato groups G1,G2 | ||
- user xdb insecure-password hello groups G2 | ||
|
||
haproxy_listens: | ||
listen1: | ||
# rank -1 | ||
- acl invalid_src src 0.0.0.0/7 224.0.0.0/3 | ||
- acl invalid_src src_port 0:1023 | ||
- acl local_dst hdr(host) -i localhost | ||
- acl es req.fhdr(accept-language),language(es;fr;en) -m str es | ||
- acl fr req.fhdr(accept-language),language(es;fr;en) -m str fr | ||
- acl en req.fhdr(accept-language),language(es;fr;en) -m str en | ||
# rank 0, in alphabetical order | ||
- bind :80 | ||
- bind :443 ssl crt /etc/haproxy/site.pem | ||
- mode http | ||
# rank 2 | ||
- tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst } | ||
- tcp-request connection reject if { src_conn_rate gt 10 } | ||
- tcp-request connection track-sc0 src | ||
# rank 3 | ||
- block if invalid_src || local_dst | ||
# rank 4 | ||
- http-request deny if invalid_src || local_dst | ||
# rank 5, in order | ||
- reqdel ^X-Forwarded-For:.* | ||
- reqdel ^Cookie:.*SERVER= | ||
- reqpass ^Host:\ www.private\.local | ||
# rank 6 | ||
- reqadd X-Proto:\ SSL if is-ssl | ||
# rank 7 | ||
- redirect prefix https://mysite.com set-cookie SEEN=1 if !cookie_set | ||
- redirect prefix https://mysite.com if login_page !secure | ||
- redirect prefix http://mysite.com drop-query if login_page !uid_given | ||
- redirect location http://mysite.com/ if !login_page secure | ||
- redirect location / clear-cookie USERID= if logout | ||
# rank 8 | ||
- use_backend backend1 if is-app1 | ||
- use_backend backend2 if is-app2 | ||
# rank 9 | ||
- use-server www if { req_ssl_sni -i www.example.com } | ||
- use-server mail if { req_ssl_sni -i mail.example.com } | ||
- use-server imap if { req_ssl_sni -i imap.example.com } | ||
# rank 100 | ||
- server default 192.0.2.2:443 check | ||
- server imap 192.0.2.1:993 weight 0 | ||
- server mail 192.0.2.1:587 weight 0 | ||
- server www 192.0.2.1:443 weight 0 | ||
listen2: | ||
- no log |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import os | ||
|
||
import pytest | ||
import yaml | ||
|
||
from filter_plugins import haproxy | ||
|
||
|
||
@pytest.fixture | ||
def config(): | ||
config_file = os.path.join(os.path.dirname(__file__), 'fixtures', 'config.yml') | ||
return yaml.load(open(config_file)) | ||
|
||
|
||
@pytest.fixture | ||
def expected(): | ||
results_file = os.path.join(os.path.dirname(__file__), 'fixtures', 'expected.yml') | ||
return yaml.load(open(results_file)) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
('section',), | ||
[ | ||
('haproxy_defaults',), | ||
('haproxy_global',), | ||
] | ||
) | ||
def test_haproxy_single_sections(config, expected, section): | ||
assert list(haproxy.to_haproxy(config[section])) == expected[section] | ||
|
||
|
||
@pytest.mark.parametrize( | ||
('section',), | ||
[ | ||
('haproxy_mailers',), | ||
('haproxy_peers',), | ||
('haproxy_resolvers',), | ||
('haproxy_userlists',), | ||
('haproxy_listens',), | ||
] | ||
) | ||
def test_haproxy_multiple_sections(config, expected, section): | ||
for group, options in config[section].items(): | ||
assert list(haproxy.to_haproxy(options)) == expected[section][group] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,15 @@ | ||
--- | ||
- hosts: localhost | ||
|
||
roles: | ||
- { role: ansible-haproxy, | ||
haproxy_frontends: [ | ||
{ | ||
name: 'fe-mysupersite', | ||
ip: '*', | ||
port: '80', | ||
maxconn: '1000', | ||
default_backend: 'be-mysupersite', | ||
} | ||
], | ||
haproxy_backends: [ | ||
{ | ||
name: 'be-mysupersite', | ||
description: 'mysupersite is really cool', | ||
servers: [ | ||
{ | ||
name: 'be-mysupersite-01', | ||
ip: '192.168.1.100' | ||
} | ||
] | ||
} | ||
] } | ||
- role: ansible-haproxy | ||
haproxy_frontends: | ||
fe-mysupersite: | ||
bind: '*:80' | ||
maxconn: 1000 | ||
default_backend: be-mysupersite | ||
|
||
haproxy_backends: | ||
be-mysupersite: | ||
description: mysupersite is really cool | ||
server: | ||
be-mysupersite-01: 192.168.1.100 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[tox] | ||
envlist = py27,py35,py36 | ||
|
||
[testenv] | ||
deps = | ||
PyYAML | ||
pytest | ||
pytest-cov | ||
commands = | ||
pytest -vv --cov=filter_plugins |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,235 +1,2 @@ | ||
--- | ||
|
||
empty: true | ||
#haproxy_global: | ||
# chroot: | ||
# pidfile: | ||
# maxconn: | ||
# user: | ||
# uid: | ||
# group: | ||
# gid: | ||
# daemon: | ||
# nbproc: | ||
# spread_checks: | ||
# stats: | ||
# socket: | ||
# timeout: | ||
# log: | ||
# - address: | ||
# facility: | ||
# level: | ||
# minlevel: | ||
# format: | ||
# ssl_default_bind_options: | ||
# ssl_default_bind_ciphers: | ||
# tune: | ||
# chksize: 32768 | ||
# ssl: | ||
# default-dh-param: 2048 | ||
# zlib: | ||
# memlevel: 9 | ||
# | ||
#haproxy_defaults: | ||
# mode: | ||
# log: | ||
# - address: | ||
# facility: | ||
# level: | ||
# minlevel: | ||
# format: | ||
# options: | ||
# - <option> | ||
# retries: | ||
# timeout: | ||
# - param: | ||
# value: | ||
# balance: | ||
# cookie: | ||
# maxconn: | ||
# stats: | ||
# enabled: | ||
# hide_version: | ||
# uri: | ||
# realm: | ||
# auth: | ||
# refresh: | ||
# compression: | ||
# algo: | ||
# type: | ||
# offload: | ||
# http_check: | ||
# disable_on_404: | ||
# expect: | ||
# send_state: | ||
# | ||
#haproxy_resolvers: | ||
# - name: | ||
# nameservers: | ||
# - name: | ||
# ip: | ||
# port: | ||
# hold: | ||
# - status: | ||
# period: | ||
# resolve_retries: | ||
# timeout_retry: | ||
# | ||
#haproxy_frontends: | ||
# - name: | ||
# ip: | ||
# bind: | ||
# - 192.168.1.1:80 | ||
# - 192.168.1.2:81 | ||
# ssl: | ||
# cert: /etc/ssl/private/cert.pem | ||
# ciphers: 'RC4-SHA:AES128-SHA:AES:!ADH:!aNULL:!DH:!EDH:!eNULL' | ||
# maxconn: | ||
# monitor: | ||
# uri: | ||
# fail: | ||
# - <condition> | ||
# condition: | ||
# - | ||
# acl: | ||
# - name: | ||
# condition: | ||
# http_request: | ||
# - action: | ||
# param: | ||
# condition: | ||
# http_response: | ||
# - action: | ||
# param: | ||
# condition: | ||
# rate_limit_sessions: | ||
# block: | ||
# - | ||
# options: | ||
# - forwardfor | ||
# default_backend: | ||
# use_backend: | ||
# - name: | ||
# condition: | ||
# timeout: | ||
# - param: | ||
# value: | ||
# reqadd: | ||
# - "X-RequestHeader1:\\ some-value" | ||
# - "X-RequestHeader2:\\ some-value" | ||
# rspadd: | ||
# - "X-ResponseHeader1:\\ some-value" | ||
# - "X-ResponseHeader2:\\ some-value" | ||
# reqrep: | ||
# - "^Host:\ www.(.*)$ Host:\ \1 if host_www" | ||
# reqirep: | ||
# - "^Host:\ www.(.*)$ Host:\ \1 if host_www" | ||
# rsprep: | ||
# - "^Location:\ 127.0.0.1:8080 Location:\ www.mydomain.com" | ||
# rspirep: | ||
# - "^Location:\ 127.0.0.1:8080 Location:\ www.mydomain.com" | ||
# force_persist: | ||
# | ||
#haproxy_backends: | ||
# - name: | ||
# disabled: | ||
# description: | ||
# balance: | ||
# cookie: | ||
# log: | ||
# retries: | ||
# contimeout: | ||
# NOTE: contimeout is deprecated | ||
# http://cbonte.github.io/haproxy-dconv/configuration-1.5.html#4-contimeout | ||
# http_send_name_header: | ||
# http_check_expect: | ||
# - condition | ||
# acl: | ||
# - name: | ||
# condition: | ||
# servers: | ||
# - name: | ||
# ip: | ||
# port: | ||
# maxconn: | ||
# params: | ||
# - param1 | ||
# options: | ||
# - forwardfor | ||
# timeout: | ||
# - param: | ||
# value: | ||
# appsession: 'JSESSIONID len 52 timeout 3h' | ||
# errorfile: | ||
# - code: | ||
# file: | ||
# reqadd: | ||
# - "X-RequestHeader1:\\ some-value" | ||
# - "X-RequestHeader2:\\ some-value" | ||
# rspadd: | ||
# - "X-ResponseHeader1:\\ some-value" | ||
# - "X-ResponseHeader2:\\ some-value" | ||
# reqrep: | ||
# - "^Host:\ www.(.*)$ Host:\ \1 if host_www" | ||
# reqirep: | ||
# - "^Host:\ www.(.*)$ Host:\ \1 if host_www" | ||
# rsprep: | ||
# - "^Location:\ 127.0.0.1:8080 Location:\ www.mydomain.com" | ||
# rspirep: | ||
# - "^Location:\ 127.0.0.1:8080 Location:\ www.mydomain.com" | ||
# force_persist: | ||
# | ||
#haproxy_listen: | ||
# - name: | ||
# bind: | ||
# ssl: | ||
# cert: /etc/ssl/private/cert.pem | ||
# ciphers: 'RC4-SHA:AES128-SHA:AES:!ADH:!aNULL:!DH:!EDH:!eNULL' | ||
# disabled: | ||
# description: | ||
# maxconn: | ||
# balance: | ||
# cookie: | ||
# log: | ||
# retries: | ||
# http_send_name_header: | ||
# http_check_expect: | ||
# - condition | ||
# acl: | ||
# - name: | ||
# condition: | ||
# servers: | ||
# - name: | ||
# ip: | ||
# port: | ||
# maxconn: | ||
# params: | ||
# - param1 | ||
# options: | ||
# - forwardfor | ||
# timeout: | ||
# - param: | ||
# value: | ||
# reqadd: | ||
# - "X-RequestHeader1:\\ some-value" | ||
# - "X-RequestHeader2:\\ some-value" | ||
# rspadd: | ||
# - "X-ResponseHeader1:\\ some-value" | ||
# - "X-ResponseHeader2:\\ some-value" | ||
# reqrep: | ||
# - "^Host:\ www.(.*)$ Host:\ \1 if host_www" | ||
# reqirep: | ||
# - "^Host:\ www.(.*)$ Host:\ \1 if host_www" | ||
# rsprep: | ||
# - "^Location:\ 127.0.0.1:8080 Location:\ www.mydomain.com" | ||
# rspirep: | ||
# - "^Location:\ 127.0.0.1:8080 Location:\ www.mydomain.com" | ||
# appsession: 'JSESSIONID len 52 timeout 3h' | ||
# stats: | ||
# enabled: | ||
# hide_version: | ||
# uri: | ||
# realm: | ||
# auth: | ||
# refresh: | ||
# force_persist: |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'items()' will produce error: AnsibleUndefinedVariable: 'list object' has no attribute 'items'
Vars: