├── .gitignore
├── .gitreview
├── CONTRIBUTING.rst
├── LICENSE
├── README.rst
├── Vagrantfile
├── bindep.txt
├── defaults
└── main.yml
├── doc
├── Makefile
├── requirements.txt
└── source
│ ├── _static
│ └── .gitkeep
│ ├── conf.py
│ ├── configure-haproxy.rst
│ └── index.rst
├── examples
└── playbook.yml
├── files
└── haproxy.default
├── handlers
└── main.yml
├── manual-test.rc
├── meta
├── main.yml
└── openstack-ansible.yml
├── releasenotes
├── notes
│ ├── .placeholder
│ ├── backend_config_per_host-14cec3ec5f708934.yaml
│ ├── bind_interface-8f7a123d4ab1219a.yaml
│ ├── cert_per_ip-e473f853dbe4047d.yaml
│ ├── certbot-auto-5ccf2184fb554c90.yaml
│ ├── certbot_ha-83b56aed3f360dba.yaml
│ ├── custom-stick-tables-1c790fe223bb0d5d.yaml
│ ├── default_backend_override-9840dc75ff9d1a9c.yaml
│ ├── disable-sslv3-303acdcc6b593180.yaml
│ ├── h2_initial_support-99a3277939942405.yaml
│ ├── haproxy-backend-arguments-3b1dca299c7a8296.yaml
│ ├── haproxy-bind-override-9562bab32b964de2.yaml
│ ├── haproxy-frontend-only-haproxy_raw-d55ad3baa8d006f3.yaml
│ ├── haproxy-hatop-4d6525a52f93a69e.yaml
│ ├── haproxy-maps-787084d7f161c27e.yaml
│ ├── haproxy-selinux-all-ports-4094eed48f2bfbca.yaml
│ ├── haproxy_allowlist-95aa9b911baeacd9.yaml
│ ├── haproxy_custom_errorfiles-500674edcaa6cbb6.yaml
│ ├── haproxy_frontend_raw-0811d5d445a66b41.yaml
│ ├── haproxy_letsencrypt-4a13c7911a20b993.yaml
│ ├── haproxy_pki_create_certificates-28dd48424855f463.yaml
│ ├── haproxy_rise_fall-64ba2e6d7e206973.yaml
│ ├── haproxy_ssl_path-7130354314aee961.yaml
│ ├── haproxy_sysctl_location-e18310fd96597a6f.yaml
│ ├── haproxy_tuning_params_released-45eb40104747561a.yaml
│ ├── implement_tuning_params-e627c774c0d0c9d2.yaml
│ ├── letsencrypt-ssl-certification-129a80cb88d8e6ff.yaml
│ ├── non_inventory_hosts-c0fa4c185a01e78b.yaml
│ ├── package-list-name-changes-a26d94a44c24de2f.yaml
│ ├── pki-temp-certs-path-d63091df0234df2e.yaml
│ ├── refresh-interval-configuration-option-884d64aa259ecc3c.yaml
│ ├── remove-haproxy-repo-vars-051a47bbfaf6d1da.yaml
│ ├── rename_haproxy_vip_binds-dda8197aaf607b53.yaml
│ ├── separated-haproxy-config-b38d200ee0baaeac.yaml
│ ├── stick-table-9ef4bd94a4a000b3.yaml
│ ├── tls12-only-a22d5f3f8198617f.yaml
│ └── tls_variables-91160d4e38085de4.yaml
└── source
│ ├── _static
│ └── .placeholder
│ ├── _templates
│ └── .placeholder
│ ├── conf.py
│ ├── index.rst
│ ├── newton.rst
│ ├── ocata.rst
│ ├── pike.rst
│ ├── queens.rst
│ ├── rocky.rst
│ ├── stein.rst
│ ├── train.rst
│ ├── unreleased.rst
│ ├── ussuri.rst
│ ├── victoria.rst
│ └── zed.rst
├── run_tests.sh
├── tasks
├── haproxy_install.yml
├── haproxy_post_install.yml
├── haproxy_pre_install.yml
├── haproxy_service_config.yml
├── haproxy_service_config_external.yml
├── haproxy_ssl_letsencrypt.yml
└── main.yml
├── templates
├── haproxy.cfg.j2
├── letsencrypt_pre_hook_certbot_distro.j2
├── letsencrypt_renew_certbot_distro.j2
├── map.j2
├── service-redirect.j2
└── service.j2
├── tests
├── ansible-role-requirements.yml
├── host_vars
│ └── localhost.yml
├── inventory
├── test-vars.yml
└── test.yml
├── tox.ini
├── vars
├── debian.yml
├── main.yml
└── redhat.yml
└── zuul.d
└── project.yaml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Add patterns in here to exclude files created by tools integrated with this
2 | # repository, such as test frameworks from the project's recommended workflow,
3 | # rendered documentation and package builds.
4 | #
5 | # Don't add patterns to exclude files created by preferred personal tools
6 | # (editors, IDEs, your operating system itself even). These should instead be
7 | # maintained outside the repository, for example in a ~/.gitignore file added
8 | # with:
9 | #
10 | # git config --global core.excludesfile '~/.gitignore'
11 |
12 | # Compiled source #
13 | ###################
14 | *.com
15 | *.class
16 | *.dll
17 | *.exe
18 | *.o
19 | *.so
20 | *.pyc
21 | build/
22 | dist/
23 | doc/build/
24 |
25 | # Packages #
26 | ############
27 | # it's better to unpack these files and commit the raw source
28 | # git has its own built in compression methods
29 | *.7z
30 | *.dmg
31 | *.gz
32 | *.iso
33 | *.jar
34 | *.rar
35 | *.tar
36 | *.zip
37 |
38 | # Logs and databases #
39 | ######################
40 | *.log
41 | *.sql
42 | *.sqlite
43 | logs/*
44 |
45 | # OS generated files #
46 | ######################
47 | ._*
48 | .ansible
49 | .tox
50 | *.egg-info
51 | .eggs
52 |
53 | # Generated by pbr while building docs
54 | ######################################
55 | AUTHORS
56 | ChangeLog
57 |
58 | # Files created by releasenotes build
59 | releasenotes/build
60 |
61 | # Test temp files
62 | tests/common
63 | tests/*.retry
64 |
65 | # Vagrant artifacts
66 | .vagrant
67 |
68 | # Git clones
69 | openstack-ansible-ops
70 | previous
71 |
--------------------------------------------------------------------------------
/.gitreview:
--------------------------------------------------------------------------------
1 | [gerrit]
2 | host=review.opendev.org
3 | port=29418
4 | project=openstack/openstack-ansible-haproxy_server.git
5 |
--------------------------------------------------------------------------------
/CONTRIBUTING.rst:
--------------------------------------------------------------------------------
1 | The source repository for this project can be found at:
2 |
3 | https://opendev.org/openstack/openstack-ansible-haproxy_server
4 |
5 | Pull requests submitted through GitHub are not monitored.
6 |
7 | To start contributing to OpenStack, follow the steps in the contribution guide
8 | to set up and use Gerrit:
9 |
10 | https://docs.openstack.org/contributors/code-and-documentation/quick-start.html
11 |
12 | Bugs should be filed on Launchpad:
13 |
14 | https://bugs.launchpad.net/openstack-ansible
15 |
16 | For more specific information about contributing to this repository, see the
17 | openstack-ansible contributor guide:
18 |
19 | https://docs.openstack.org/openstack-ansible/latest/contributor/contributing.html
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | ================================
2 | OpenStack-Ansible HAProxy server
3 | ================================
4 |
5 | This Ansible role install the HAProxy Load Balancer service.
6 |
7 | Documentation for the project can be found at:
8 | https://docs.openstack.org/openstack-ansible-haproxy_server/latest
9 |
10 | Release notes for the project can be found at:
11 | https://docs.openstack.org/releasenotes/openstack-ansible-haproxy_server/
12 |
13 | The project source code repository is located at:
14 | https://opendev.org/openstack/openstack-ansible-haproxy_server/
15 |
16 | The project home is at:
17 | https://launchpad.net/openstack-ansible
18 |
19 | The project bug tracker is located at:
20 | https://bugs.launchpad.net/openstack-ansible
21 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # Note:
2 | # This file is maintained in the openstack-ansible-tests repository.
3 | # https://opendev.org/openstack/openstack-ansible-tests/src/Vagrantfile
4 | #
5 | # If you need to perform any change on it, you should modify the central file,
6 | # then, an OpenStack CI job will propagate your changes to every OSA repository
7 | # since every repo uses the same Vagrantfile
8 |
9 | # Verify whether required plugins are installed.
10 | required_plugins = [ "vagrant-disksize" ]
11 | required_plugins.each do |plugin|
12 | if not Vagrant.has_plugin?(plugin)
13 | raise "The vagrant plugin #{plugin} is required. Please run `vagrant plugin install #{plugin}`"
14 | end
15 | end
16 |
17 | Vagrant.configure(2) do |config|
18 | config.vm.provider "virtualbox" do |v|
19 | v.memory = 6144
20 | v.cpus = 2
21 | # https://github.com/hashicorp/vagrant/issues/9524
22 | v.customize ["modifyvm", :id, "--audio", "none"]
23 | end
24 |
25 | config.vm.synced_folder ".", "/vagrant", type: "rsync"
26 |
27 | config.vm.provision "shell",
28 | privileged: false,
29 | inline: <<-SHELL
30 | cd /vagrant
31 | ./run_tests.sh
32 | SHELL
33 |
34 | config.vm.define "centos8" do |centos8|
35 | centos8.vm.box = "centos/8"
36 | end
37 |
38 | config.vm.define "debian10" do |debian10|
39 | debian10.vm.box = "debian/buster64"
40 | end
41 |
42 | config.vm.define "ubuntu2004" do |focal|
43 | focal.disksize.size = "40GB"
44 | focal.vm.box = "ubuntu/focal64"
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/bindep.txt:
--------------------------------------------------------------------------------
1 | # This file facilitates OpenStack-CI package installation
2 | # before the execution of any tests.
3 | #
4 | # See the following for details:
5 | # - https://docs.openstack.org/infra/bindep/
6 | # - https://opendev.org/openstack-infra/bindep
7 | #
8 | # Even if the role does not make use of this facility, it
9 | # is better to have this file empty, otherwise OpenStack-CI
10 | # will fall back to installing its default packages which
11 | # will potentially be detrimental to the tests executed.
12 | #
13 | # Note:
14 | # This file is maintained in the openstack-ansible-tests repository.
15 | # https://opendev.org/openstack/openstack-ansible-tests/src/bindep.txt
16 | # If you need to remove or add extra dependencies, you should modify
17 | # the central file instead and once your change is accepted then update
18 | # this file as well. The purpose of this file is to ensure that Python and
19 | # Ansible have all their necessary binary requirements on the test host before
20 | # tox executes. Any binary requirements needed by services/roles should be
21 | # installed by those roles in their applicable package install tasks, not through
22 | # using this file.
23 | #
24 |
25 | # The gcc compiler
26 | gcc
27 |
28 | # Base requirements for Ubuntu
29 | git-core [platform:dpkg]
30 | libssl-dev [platform:dpkg]
31 | libffi-dev [platform:dpkg]
32 | python3 [platform:dpkg]
33 | python3-apt [platform:dpkg]
34 | python3-dev [platform:dpkg]
35 |
36 | # Base requirements for RPM distros
37 | gcc-c++ [platform:rpm]
38 | git [platform:rpm]
39 | libffi-devel [platform:rpm]
40 | openssl-devel [platform:rpm]
41 | python3-dnf [platform:fedora]
42 | python3-devel [platform:rpm]
43 |
44 | # For SELinux
45 | libselinux-python3 [platform:redhat]
46 | libsemanage-python3 [platform:redhat]
47 | iptables [platform:redhat]
48 |
--------------------------------------------------------------------------------
/defaults/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2014, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | # Validate Certificates when downloading hatop. May be set to "no" when proxy server
17 | # is intercepting the certificates.
18 | haproxy_hatop_download_validate_certs: true
19 |
20 | # Set the package install state for distribution packages
21 | # Options are 'present' and 'latest'
22 | haproxy_package_state: "latest"
23 |
24 | ## Haproxy Configuration
25 | haproxy_rise: 3
26 | haproxy_fall: 3
27 | haproxy_interval: 12000
28 |
29 | ## Haproxy Stats
30 | haproxy_stats_enabled: false
31 | haproxy_stats_bind_address: 127.0.0.1
32 | haproxy_stats_port: 1936
33 | haproxy_stats_ssl: "{{ haproxy_ssl }}"
34 | # haproxy_stats_ssl_cert_path: "{{ haproxy_ssl_cert_path }}/somecustomstatscert.pem"
35 | # haproxy_stats_ssl_client_cert_ca: "{{ haproxy_ssl_cert_path }}/somecustomrootca.pem"
36 | haproxy_username: admin
37 | haproxy_stats_password: secrete
38 | haproxy_stats_refresh_interval: 60
39 | # Prometheus stats are supported from HAProxy v2
40 | # Stats must be enabled above before this can be used
41 | haproxy_stats_prometheus_enabled: false
42 |
43 | # Default haproxy backup nodes to empty list so this doesn't have to be
44 | # defined for each service.
45 | haproxy_backup_nodes: []
46 |
47 | # Configuration lines to write directly into all frontends
48 | haproxy_frontend_extra_raw: []
49 | haproxy_frontend_redirect_extra_raw: "{{ haproxy_frontend_extra_raw }}"
50 |
51 | # Default values for enabling HTTP/2 support
52 | # Note, that while HTTP/2 will be enabled on frontends that are covered with TLS,
53 | # backends can be configured to use HTTP/2 regardless of TLS.
54 | haproxy_frontend_h2: true
55 | haproxy_backend_h2: false
56 |
57 | haproxy_service_configs: []
58 | # Example:
59 | # haproxy_service_configs:
60 | # - haproxy_service_name: haproxy_all
61 | # haproxy_backend_nodes: "{{ groups['haproxy_all'][0] }}"
62 | # # haproxy_backup_nodes: "{{ groups['haproxy_all'][1:] }}"
63 | # haproxy_port: 80
64 | # haproxy_balance_type: http
65 | # haproxy_backend_options:
66 | # - "forwardfor"
67 | # - "httpchk"
68 | # - "httplog"
69 | # haproxy_backend_server_options:
70 | # - "inter 3000" # a contrived example, there are many server config options possible
71 | # haproxy_acls:
72 | # allow_list:
73 | # rule: "src 127.0.0.1/8 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8"
74 | # backend_name: "mybackend"
75 | # haproxy_frontend_h2: True
76 | # haproxy_backend_h2: False
77 | # haproxy_frontend_acls:
78 | # letsencrypt-acl:
79 | # rule: "path_beg /.well-known/acme-challenge/"
80 | # backend_name: letsencrypt
81 | # haproxy_stick_table:
82 | # - "stick-table type ipv6 size 256k expire 10s store http_err_rate(10s)"
83 | # - "http-request track-sc0 src"
84 | # - "http-request deny deny_status 429 if { sc_http_err_rate(0) gt 20 } !{ src 10.0.0.0/8 } !{ src 172.16.0.0/12 } !{ src 192.168.0.0/16 }"
85 | # # https://www.haproxy.com/blog/haproxy-exposes-a-prometheus-metrics-endpoint/
86 | # - haproxy_service_name: prometheus-metrics
87 | # haproxy_port: 8404
88 | # haproxy_bind:
89 | # - '127.0.0.1'
90 | # haproxy_allowlist_networks: "{{ haproxy_allowlist_networks }}"
91 | # haproxy_frontend_only: True
92 | # haproxy_balance_type: "http"
93 | # haproxy_frontend_raw:
94 | # - 'http-request use-service prometheus-exporter if { path /metrics }'
95 | # haproxy_service_enabled: True
96 |
97 | # HAProxy maps (unrelated keys are omitted but are required as the previous service example)
98 | # Example:
99 | # haproxy_service_configs:
100 | # - state: present # state 'absent' will remove map entries defined in this service
101 | # haproxy_service_enabled: true # haproxy_service_enabled 'false' will remove map entries defined in this service
102 | # haproxy_service_name: "one"
103 | # haproxy_maps:
104 | # - 'use_backend %[req.hdr(host),lower,map(/etc/haproxy/route.map)]'
105 | # haproxy_map_entries:
106 | # - name: 'route' # this service contributes entries to the map called 'route'
107 | # order: 10 # prefix the name of the map fragment wih this string to control ordering of the assembled map
108 | # entries:
109 | # - compute.example.com nova-api
110 | # - dashboard.example.com horizon
111 | # - haproxy_service_name: "two"
112 | # - haproxy_service_name: "three"
113 | # haproxy_map_entries:
114 | # - name: 'route' # this service contributes to the map called 'route'
115 | # entries:
116 | # - s3.example.com radosgw
117 | # - sso.example.com keycloak
118 | # - name: 'rate' # and also to the map called 'rate'
119 | # state: present # individual map entries can be removed with state 'absent'
120 | # entries:
121 | # - /api/foo 20
122 | # - /api/bar 40
123 | #
124 | # Results:
125 | #
126 | # /etc/haproxy/route.map
127 | # s3.example.com radosgw
128 | # sso.example.com keycloak
129 | # compute.example.com nova-api
130 | # dashboard.example.com horizon
131 | #
132 | # /etc/haproxy/rate.map
133 | # /api/foo 20
134 | # /api/bar 40
135 |
136 | galera_monitoring_user: monitoring
137 | haproxy_bind_on_non_local: false
138 |
139 | ## haproxy SSL
140 | haproxy_ssl: true
141 | haproxy_ssl_all_vips: false
142 | haproxy_ssl_dh_param: 2048
143 | haproxy_ssl_cert_path: /etc/haproxy/ssl
144 | haproxy_ssl_temp_path: "{{ haproxy_ssl_cert_path }}"
145 | haproxy_ssl_bind_options: "ssl-min-ver TLSv1.2 prefer-client-ciphers"
146 | haproxy_ssl_server_options: "ssl-min-ver TLSv1.2"
147 | # TLS v1.2 and below
148 | haproxy_ssl_cipher_suite_tls12: >-
149 | {{ haproxy_ssl_cipher_suite | default(ssl_cipher_suite_tls12 | default('ECDH+AESGCM:ECDH+CHACHA20:ECDH+AES256:ECDH+AES128:!aNULL:!SHA1:!AESCCM')) }}
150 | # TLS v1.3
151 | haproxy_ssl_cipher_suite_tls13: "{{ ssl_cipher_suite_tls13 | default('TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256') }}"
152 |
153 | # haproxy self signed certificate
154 |
155 | # Storage location for SSL certificate authority
156 | haproxy_pki_dir: "{{ openstack_pki_dir | default('/etc/pki/haproxy-ca') }}"
157 |
158 | # Delegated host for operating the certificate authority
159 | haproxy_pki_setup_host: "{{ openstack_pki_setup_host | default('localhost') }}"
160 |
161 | # Create a certificate authority if one does not already exist
162 | haproxy_pki_create_ca: "{{ openstack_pki_authorities is not defined | bool }}"
163 | haproxy_pki_regen_ca: ""
164 | haproxy_pki_authorities:
165 | - name: "HAProxyRoot"
166 | country: "GB"
167 | state_or_province_name: "England"
168 | organization_name: "Example Corporation"
169 | organizational_unit_name: "IT Security"
170 | cn: "HAProxy Root CA"
171 | provider: selfsigned
172 | basic_constraints: "CA:TRUE"
173 | key_usage:
174 | - digitalSignature
175 | - cRLSign
176 | - keyCertSign
177 | not_after: "+3650d"
178 | - name: "HAProxyIntermediate"
179 | country: "GB"
180 | state_or_province_name: "England"
181 | organization_name: "Example Corporation"
182 | organizational_unit_name: "IT Security"
183 | cn: "HAProxy Intermediate CA"
184 | provider: ownca
185 | basic_constraints: "CA:TRUE,pathlen:0"
186 | key_usage:
187 | - digitalSignature
188 | - cRLSign
189 | - keyCertSign
190 | not_after: "+3650d"
191 | signed_by: "HAProxyRoot"
192 |
193 | # Installation details for certificate authorities
194 | haproxy_pki_install_ca:
195 | - name: "HAProxyRoot"
196 | condition: "{{ haproxy_pki_create_ca }}"
197 |
198 | # HAProxy server certificate
199 | haproxy_pki_keys_path: "{{ haproxy_pki_dir ~ '/certs/private/' }}"
200 | haproxy_pki_certs_path: "{{ haproxy_pki_dir ~ '/certs/certs/' }}"
201 | haproxy_pki_intermediate_cert_name: "{{ openstack_pki_service_intermediate_cert_name | default('HAProxyIntermediate') }}"
202 | haproxy_pki_intermediate_cert_path: >-
203 | {{ haproxy_pki_dir ~ '/roots/' ~ haproxy_pki_intermediate_cert_name ~ '/certs/' ~ haproxy_pki_intermediate_cert_name ~ '.crt' }}
204 | haproxy_pki_regen_cert: ""
205 | haproxy_pki_certificates: "{{ _haproxy_pki_certificates }}"
206 |
207 | # SSL certificate creation
208 | haproxy_pki_create_certificates: "{{ haproxy_user_ssl_cert is not defined and haproxy_user_ssl_key is not defined }}"
209 |
210 | # Installation details for SSL certificates
211 | haproxy_pki_install_certificates: "{{ _haproxy_pki_install_certificates }}"
212 |
213 | # activate letsencrypt option
214 | haproxy_ssl_letsencrypt_enable: false
215 | haproxy_ssl_letsencrypt_certbot_binary: "certbot"
216 | haproxy_ssl_letsencrypt_certbot_backend_port: 8888
217 | haproxy_ssl_letsencrypt_pre_hook_timeout: 5
218 | haproxy_ssl_letsencrypt_certbot_bind_address: "{{ ansible_host }}"
219 | haproxy_ssl_letsencrypt_certbot_challenge: "http-01"
220 | haproxy_ssl_letsencrypt_email: "example@example.com"
221 | haproxy_ssl_letsencrypt_config_path: "/etc/letsencrypt/live"
222 | haproxy_ssl_letsencrypt_setup_extra_params: ""
223 | haproxy_ssl_letsencrypt_acl:
224 | letsencrypt-acl:
225 | rule: "path_beg /.well-known/acme-challenge/"
226 | backend_name: letsencrypt
227 | # Use alternative CA that supports ACME, can be a public or private CA
228 | # haproxy_ssl_letsencrypt_certbot_server: "https://acme-staging-v02.api.letsencrypt.org/directory"
229 | haproxy_ssl_letsencrypt_domains:
230 | - "{{ external_lb_vip_address }}"
231 |
232 | # hatop extra package URL and checksum
233 | haproxy_hatop_download_url: "https://github.com/jhunt/hatop/archive/refs/tags/v0.8.2.tar.gz"
234 | haproxy_hatop_download_checksum: "sha256:7fac1f593f92b939cfce34175b593e43862eee8e25db251d03a910b37721fc5d"
235 |
236 | # Install hatop
237 | haproxy_hatop_install: true
238 |
239 | # The location where the extra packages are downloaded to
240 | haproxy_hatop_download_path: "/opt/cache/files"
241 |
242 | ## haproxy default
243 | # Set the number of retries to perform on a server after a connection failure
244 | haproxy_retries: "3"
245 | # Set the maximum inactivity time on the client side
246 | haproxy_client_timeout: "50s"
247 | # Set the maximum time to wait for a connection attempt to a server to succeed
248 | haproxy_connect_timeout: "10s"
249 | # Set the maximum allowed time to wait for a complete HTTP request
250 | haproxy_http_request_timeout: "5s"
251 | # Set the maximum inactivity time on the server side
252 | haproxy_server_timeout: "50s"
253 | # Set the HTTP keepalive mode to use
254 | # Disable persistent connections by default because they can cause issues when the server side closes the connection
255 | # at the same time a request is sent.
256 | haproxy_keepalive_mode: "httpclose"
257 |
258 | ## haproxy tuning params
259 | haproxy_maxconn: 4096
260 |
261 | # Parameters below should only be specified if necessary, defaults are programmed in the template
262 | # haproxy_tuning_params:
263 | # tune.bufsize: 384000
264 | # tune.chksize: 16384
265 | # tune.comp_maxlevel: 1
266 | # tune.http_maxhdr: 101
267 | # tune.maxaccept: 64
268 | # tune.ssl_cachesize: 20000
269 | # tune.ssl_lifetime: 300
270 | haproxy_tuning_params: {}
271 |
272 | # Add extra VIPs to all services
273 | extra_lb_vip_addresses: []
274 |
275 | # Add extra TLS VIPs to all services
276 | extra_lb_tls_vip_addresses: []
277 |
278 | # Option to override which address haproxy binds to for external vip.
279 | haproxy_bind_external_lb_vip_address: "{{ external_lb_vip_address }}"
280 |
281 | # Option to override which address haproxy binds to for internal vip.
282 | haproxy_bind_internal_lb_vip_address: "{{ internal_lb_vip_address }}"
283 |
284 | # Option to define if you need haproxy to bind on specific interface.
285 | haproxy_bind_external_lb_vip_interface:
286 | haproxy_bind_internal_lb_vip_interface:
287 |
288 | # Option to override haproxy frontend binds
289 | # Example:
290 | # haproxy_vip_binds:
291 | # - address: '*'
292 | # interface: bond0
293 | # type: external
294 | # - address: '192.168.0.10'
295 | # pki_san_records:
296 | # - internal.cloud
297 | haproxy_vip_binds: "{{ haproxy_tls_vip_binds | default(_haproxy_vip_binds) }}"
298 |
299 | # Make the log socket available to the chrooted filesystem
300 | haproxy_log_socket: "/dev/log"
301 | haproxy_log_mount_point: "/var/lib/haproxy/dev/log"
302 |
303 | # Ansible group name which should be used for distrtibuting self signed SSL Certificates
304 | haproxy_ansible_group_name: haproxy_all
305 |
306 | ## security.txt
307 | # When security risks in web services are discovered by independent security
308 | # researchers who understand the severity of the risk, they often lack the
309 | # channels to disclose them properly. As a result, security issues may be
310 | # left unreported. security.txt defines a standard to help organizations
311 | # define the process for security researchers to disclose security
312 | # vulnerabilities securely. For more information see https://securitytxt.org/
313 | # This content will be hosted at /security.txt and /.well-known/security.txt
314 | haproxy_security_txt_dir: "/etc/haproxy"
315 | haproxy_security_txt_headers: |
316 | HTTP/1.0 200 OK
317 | Cache-Control: no-cache
318 | Connection: close
319 | Content-Type: text/plain; charset=utf-8
320 |
321 | haproxy_security_txt_content: ""
322 | # haproxy_security_txt_content: |
323 | # # Please see https://securitytxt.org/ for details of the specification of this file
324 |
325 | # Allows to copy any static file to the destination hosts
326 | haproxy_static_files_default:
327 | - dest: "{{ haproxy_security_txt_dir }}/security.txt"
328 | content: "{{ haproxy_security_txt_headers + '\n' + haproxy_security_txt_content }}"
329 | condition: "{{ haproxy_security_txt_content is truthy }}"
330 | haproxy_static_files_extra: []
331 | haproxy_static_files: "{{ haproxy_static_files_default + haproxy_static_files_extra }}"
332 |
333 | haproxy_sysctl_file: "{{ openstack_sysctl_file | default('/etc/sysctl.conf') }}"
334 |
335 | # Allows to define custom errorfiles in the format:
336 | # - code: 504
337 | # path: /path/to/504.http
338 | # You can use haproxy_static_files_extra to add those files.
339 | # See https://github.com/haproxy/haproxy/tree/master/examples/errorfiles for examples
340 | #
341 | # An example combination of haproxy_static_files_extra and haproxy_errorfiles:
342 | # haproxy_static_files_extra:
343 | # - dest: /etc/haproxy/500.http
344 | # content: |
345 | # HTTP/1.0 500 Internal Server Error
346 | # Cache-Control: no-cache
347 | # Connection: close
348 | # Content-Type: text/html
349 | #
350 | #
500 Internal Server Error
351 | # This Server Made a Boo Boo
352 | #
353 | # - dest: /etc/haproxy/504.http
354 | # content: "{{ lookup('file', '/etc/openstack_deploy/haproxy/504.http') }}"
355 | #
356 | # haproxy_errorfiles:
357 | # - code: 500
358 | # path: /etc/haproxy/500.http
359 | # - code: 504
360 | # path: /etc/haproxy/504.http
361 | #
362 | haproxy_errorfiles: []
363 |
--------------------------------------------------------------------------------
/doc/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = build
9 |
10 | # User-friendly check for sphinx-build
11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
13 | endif
14 |
15 | # Internal variables.
16 | PAPEROPT_a4 = -D latex_paper_size=a4
17 | PAPEROPT_letter = -D latex_paper_size=letter
18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
19 | # the i18n builder cannot share the environment and doctrees with the others
20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
21 |
22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
23 |
24 | help:
25 | @echo "Please use \`make ' where is one of"
26 | @echo " html to make standalone HTML files"
27 | @echo " dirhtml to make HTML files named index.html in directories"
28 | @echo " singlehtml to make a single large HTML file"
29 | @echo " pickle to make pickle files"
30 | @echo " json to make JSON files"
31 | @echo " htmlhelp to make HTML files and a HTML help project"
32 | @echo " qthelp to make HTML files and a qthelp project"
33 | @echo " applehelp to make an Apple Help Book"
34 | @echo " devhelp to make HTML files and a Devhelp project"
35 | @echo " epub to make an epub"
36 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
37 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
38 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
39 | @echo " text to make text files"
40 | @echo " man to make manual pages"
41 | @echo " texinfo to make Texinfo files"
42 | @echo " info to make Texinfo files and run them through makeinfo"
43 | @echo " gettext to make PO message catalogs"
44 | @echo " changes to make an overview of all changed/added/deprecated items"
45 | @echo " xml to make Docutils-native XML files"
46 | @echo " pseudoxml to make pseudoxml-XML files for display purposes"
47 | @echo " linkcheck to check all external links for integrity"
48 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
49 | @echo " coverage to run coverage check of the documentation (if enabled)"
50 |
51 | clean:
52 | rm -rf $(BUILDDIR)/*
53 |
54 | html:
55 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
56 | @echo
57 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
58 |
59 | dirhtml:
60 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
61 | @echo
62 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
63 |
64 | singlehtml:
65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
66 | @echo
67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
68 |
69 | pickle:
70 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
71 | @echo
72 | @echo "Build finished; now you can process the pickle files."
73 |
74 | json:
75 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
76 | @echo
77 | @echo "Build finished; now you can process the JSON files."
78 |
79 | htmlhelp:
80 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
81 | @echo
82 | @echo "Build finished; now you can run HTML Help Workshop with the" \
83 | ".hhp project file in $(BUILDDIR)/htmlhelp."
84 |
85 | qthelp:
86 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
87 | @echo
88 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
89 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
90 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/openstack-ansible-haproxy_server.qhcp"
91 | @echo "To view the help file:"
92 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/openstack-ansible-haproxy_server.qhc"
93 |
94 | applehelp:
95 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
96 | @echo
97 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
98 | @echo "N.B. You won't be able to view it unless you put it in" \
99 | "~/Library/Documentation/Help or install it in your application" \
100 | "bundle."
101 |
102 | devhelp:
103 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
104 | @echo
105 | @echo "Build finished."
106 | @echo "To view the help file:"
107 | @echo "# mkdir -p $$HOME/.local/share/devhelp/openstack-ansible-haproxy_server"
108 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/openstack-ansible-haproxy_server"
109 | @echo "# devhelp"
110 |
111 | epub:
112 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
113 | @echo
114 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
115 |
116 | latex:
117 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
118 | @echo
119 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
120 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
121 | "(use \`make latexpdf' here to do that automatically)."
122 |
123 | latexpdf:
124 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
125 | @echo "Running LaTeX files through pdflatex..."
126 | $(MAKE) -C $(BUILDDIR)/latex all-pdf
127 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
128 |
129 | latexpdfja:
130 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
131 | @echo "Running LaTeX files through platex and dvipdfmx..."
132 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
133 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
134 |
135 | text:
136 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
137 | @echo
138 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
139 |
140 | man:
141 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
142 | @echo
143 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
144 |
145 | texinfo:
146 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
147 | @echo
148 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
149 | @echo "Run \`make' in that directory to run these through makeinfo" \
150 | "(use \`make info' here to do that automatically)."
151 |
152 | info:
153 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
154 | @echo "Running Texinfo files through makeinfo..."
155 | make -C $(BUILDDIR)/texinfo info
156 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
157 |
158 | gettext:
159 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
160 | @echo
161 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
162 |
163 | changes:
164 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
165 | @echo
166 | @echo "The overview file is in $(BUILDDIR)/changes."
167 |
168 | linkcheck:
169 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
170 | @echo
171 | @echo "Link check complete; look for any errors in the above output " \
172 | "or in $(BUILDDIR)/linkcheck/output.txt."
173 |
174 | doctest:
175 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
176 | @echo "Testing of doctests in the sources finished, look at the " \
177 | "results in $(BUILDDIR)/doctest/output.txt."
178 |
179 | coverage:
180 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
181 | @echo "Testing of coverage in the sources finished, look at the " \
182 | "results in $(BUILDDIR)/coverage/python.txt."
183 |
184 | xml:
185 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
186 | @echo
187 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
188 |
189 | pseudoxml:
190 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
191 | @echo
192 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
193 |
194 | livehtml: html
195 | sphinx-autobuild -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
196 |
--------------------------------------------------------------------------------
/doc/requirements.txt:
--------------------------------------------------------------------------------
1 | # The order of packages is significant, because pip processes them in the order
2 | # of appearance. Changing the order has an impact on the overall integration
3 | # process, which may cause wedges in the gate later.
4 |
5 | # WARNING:
6 | # This file is maintained in the openstack-ansible-tests repository.
7 | # https://opendev.org/openstack/openstack-ansible-tests/src/branch/master/sync/doc/requirements.txt
8 | # If you need to modify this file, update the one in the
9 | # openstack-ansible-tests repository. Once it merges there, the changes will
10 | # automatically be proposed to all the repositories which use it.
11 |
12 | sphinx>=2.0.0,!=2.1.0 # BSD
13 | sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD
14 | openstackdocstheme>=2.2.1 # Apache-2.0
15 | reno>=3.1.0 # Apache-2.0
16 | doc8>=0.6.0 # Apache-2.0
17 |
--------------------------------------------------------------------------------
/doc/source/_static/ .gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/openstack-ansible-haproxy_server/abf058c556f223f2102ab2491f2bb7b9e6f048df/doc/source/_static/ .gitkeep
--------------------------------------------------------------------------------
/doc/source/conf.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12 | # implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | # This file is execfile()d with the current directory set to its
17 | # containing dir.
18 | #
19 | # Note that not all possible configuration values are present in this
20 | # autogenerated file.
21 | #
22 | # All configuration values have a default; values that are commented out
23 | # serve to show the default.
24 |
25 | import openstackdocstheme
26 |
27 | # If extensions (or modules to document with autodoc) are in another directory,
28 | # add these directories to sys.path here. If the directory is relative to the
29 | # documentation root, use os.path.abspath to make it absolute, like shown here.
30 | # sys.path.insert(0, os.path.abspath('.'))
31 |
32 | # -- General configuration ------------------------------------------------
33 |
34 | # If your documentation needs a minimal Sphinx version, state it here.
35 | # needs_sphinx = '1.0'
36 |
37 | # Add any Sphinx extension module names here, as strings. They can be
38 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
39 | # ones.
40 | extensions = [
41 | 'openstackdocstheme',
42 | 'sphinx.ext.autodoc',
43 | 'sphinx.ext.extlinks',
44 | 'sphinxcontrib.rsvgconverter',
45 | ]
46 |
47 | # Add any paths that contain templates here, relative to this directory.
48 | templates_path = ['_templates']
49 |
50 | # The suffix(es) of source filenames.
51 | # You can specify multiple suffix as a list of string:
52 | # source_suffix = ['.rst', '.md']
53 | source_suffix = '.rst'
54 |
55 | # The encoding of source files.
56 | # source_encoding = 'utf-8-sig'
57 |
58 | # The master toctree document.
59 | master_doc = 'index'
60 |
61 | # General information about the project.
62 | author = 'OpenStack-Ansible Contributors'
63 | category = 'Miscellaneous'
64 | copyright = '2014-2016, OpenStack-Ansible Contributors'
65 | description = 'OpenStack-Ansible deploys OpenStack environments using Ansible.'
66 | project = 'OpenStack-Ansible'
67 | role_name = 'haproxy_server'
68 | target_name = 'openstack-ansible-' + role_name
69 | title = 'OpenStack-Ansible Documentation: ' + role_name + ' role'
70 |
71 | # References variable for substitutions
72 | current_series = openstackdocstheme.ext._get_series_name()
73 | dev_docs_prefix = "https://docs.openstack.org/openstack-ansible/{}/%s".format(
74 | current_series
75 | )
76 |
77 | # Format: Reference name: (string containing %s for substitution, linkname)
78 | extlinks = {'dev_docs': (dev_docs_prefix, '')}
79 |
80 | # openstackdocstheme options
81 | openstackdocs_repo_name = 'openstack/' + target_name
82 | openstackdocs_pdf_link = True
83 | openstackdocs_bug_project = project.lower()
84 | openstackdocs_bug_tag = ''
85 |
86 | # The language for content autogenerated by Sphinx. Refer to documentation
87 | # for a list of supported languages.
88 | #
89 | # This is also used if you do content translation via gettext catalogs.
90 | # Usually you set "language" from the command line for these cases.
91 | language = 'en'
92 |
93 | # There are two options for replacing |today|: either, you set today to some
94 | # non-false value, then it is used:
95 | # today = ''
96 | # Else, today_fmt is used as the format for a strftime call.
97 | # today_fmt = '%B %d, %Y'
98 |
99 | # List of patterns, relative to source directory, that match files and
100 | # directories to ignore when looking for source files.
101 | exclude_patterns = []
102 |
103 | # The reST default role (used for this markup: `text`) to use for all
104 | # documents.
105 | # default_role = None
106 |
107 | # If true, '()' will be appended to :func: etc. cross-reference text.
108 | # add_function_parentheses = True
109 |
110 | # If true, the current module name will be prepended to all description
111 | # unit titles (such as .. function::).
112 | # add_module_names = True
113 |
114 | # If true, sectionauthor and moduleauthor directives will be shown in the
115 | # output. They are ignored by default.
116 | # show_authors = False
117 |
118 | # The name of the Pygments (syntax highlighting) style to use.
119 | pygments_style = 'native'
120 |
121 | # A list of ignored prefixes for module index sorting.
122 | # modindex_common_prefix = []
123 |
124 | # If true, keep warnings as "system message" paragraphs in the built documents.
125 | # keep_warnings = False
126 |
127 | # If true, `todo` and `todoList` produce output, else they produce nothing.
128 | todo_include_todos = False
129 |
130 |
131 | # -- Options for HTML output ----------------------------------------------
132 |
133 | # The theme to use for HTML and HTML Help pages. See the documentation for
134 | # a list of builtin themes.
135 | html_theme = 'openstackdocs'
136 |
137 | # Theme options are theme-specific and customize the look and feel of a theme
138 | # further. For a list of options available for each theme, see the
139 | # documentation.
140 | # html_theme_options = {}
141 |
142 | # Add any paths that contain custom themes here, relative to this directory.
143 | # html_theme_path = []
144 |
145 | # The name for this set of Sphinx documents. If None, it defaults to
146 | # " v documentation".
147 | # html_title = None
148 |
149 | # A shorter title for the navigation bar. Default is the same as html_title.
150 | # html_short_title = None
151 |
152 | # The name of an image file (relative to this directory) to place at the top
153 | # of the sidebar.
154 | # html_logo = None
155 |
156 | # The name of an image file (within the static path) to use as favicon of the
157 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
158 | # pixels large.
159 | # html_favicon = None
160 |
161 | # Add any paths that contain custom static files (such as style sheets) here,
162 | # relative to this directory. They are copied after the builtin static files,
163 | # so a file named "default.css" will overwrite the builtin "default.css".
164 | html_static_path = ['_static']
165 |
166 | # Add any extra paths that contain custom files (such as robots.txt or
167 | # .htaccess) here, relative to this directory. These files are copied
168 | # directly to the root of the documentation.
169 | # html_extra_path = []
170 |
171 | # If true, SmartyPants will be used to convert quotes and dashes to
172 | # typographically correct entities.
173 | # html_use_smartypants = True
174 |
175 | # Custom sidebar templates, maps document names to template names.
176 | # html_sidebars = {}
177 |
178 | # Additional templates that should be rendered to pages, maps page names to
179 | # template names.
180 | # html_additional_pages = {}
181 |
182 | # If false, no module index is generated.
183 | # html_domain_indices = True
184 |
185 | # If false, no index is generated.
186 | # html_use_index = True
187 |
188 | # If true, the index is split into individual pages for each letter.
189 | # html_split_index = False
190 |
191 | # If true, links to the reST sources are added to the pages.
192 | # html_show_sourcelink = True
193 |
194 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
195 | # html_show_sphinx = True
196 |
197 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
198 | # html_show_copyright = True
199 |
200 | # If true, an OpenSearch description file will be output, and all pages will
201 | # contain a tag referring to it. The value of this option must be the
202 | # base URL from which the finished HTML is served.
203 | # html_use_opensearch = ''
204 |
205 | # This is the file name suffix for HTML files (e.g. ".xhtml").
206 | # html_file_suffix = None
207 |
208 | # Language to be used for generating the HTML full-text search index.
209 | # Sphinx supports the following languages:
210 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
211 | # 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr'
212 | # html_search_language = 'en'
213 |
214 | # A dictionary with options for the search language support, empty by default.
215 | # Now only 'ja' uses this config value
216 | # html_search_options = {'type': 'default'}
217 |
218 | # The name of a javascript file (relative to the configuration directory) that
219 | # implements a search results scorer. If empty, the default will be used.
220 | # html_search_scorer = 'scorer.js'
221 |
222 | # Output file base name for HTML help builder.
223 | htmlhelp_basename = target_name + '-docs'
224 |
225 | # -- Options for LaTeX output ---------------------------------------------
226 |
227 | latex_elements = {
228 | # The paper size ('letterpaper' or 'a4paper').
229 | # 'papersize': 'letterpaper',
230 |
231 | # The font size ('10pt', '11pt' or '12pt').
232 | # 'pointsize': '10pt',
233 |
234 | # Additional stuff for the LaTeX preamble.
235 | # 'preamble': '',
236 |
237 | # Latex figure (float) alignment
238 | # 'figure_align': 'htbp',
239 | }
240 |
241 | # Grouping the document tree into LaTeX files. List of tuples
242 | # (source start file, target name, title,
243 | # author, documentclass [howto, manual, or own class]).
244 | latex_documents = [
245 | (master_doc, 'doc-' + target_name + '.tex',
246 | title.replace("_", r"\_"), author, 'manual'),
247 | ]
248 |
249 | latex_use_xindy = False
250 |
251 | # The name of an image file (relative to this directory) to place at the top of
252 | # the title page.
253 | # latex_logo = None
254 |
255 | # For "manual" documents, if this is true, then toplevel headings are parts,
256 | # not chapters.
257 | # latex_use_parts = False
258 |
259 | # If true, show page references after internal links.
260 | # latex_show_pagerefs = False
261 |
262 | # If true, show URL addresses after external links.
263 | # latex_show_urls = False
264 |
265 | # Documents to append as an appendix to all manuals.
266 | # latex_appendices = []
267 |
268 | # If false, no module index is generated.
269 | # latex_domain_indices = True
270 |
271 |
272 | # -- Options for manual page output ---------------------------------------
273 |
274 | # One entry per manual page. List of tuples
275 | # (source start file, name, description, authors, manual section).
276 | man_pages = [
277 | (master_doc, target_name,
278 | title, [author], 1)
279 | ]
280 |
281 | # If true, show URL addresses after external links.
282 | # man_show_urls = False
283 |
284 |
285 | # -- Options for Texinfo output -------------------------------------------
286 |
287 | # Grouping the document tree into Texinfo files. List of tuples
288 | # (source start file, target name, title, author,
289 | # dir menu entry, description, category)
290 | texinfo_documents = [
291 | (master_doc, target_name,
292 | title, author, project,
293 | description, category),
294 | ]
295 |
296 | # Documents to append as an appendix to all manuals.
297 | # texinfo_appendices = []
298 |
299 | # If false, no module index is generated.
300 | # texinfo_domain_indices = True
301 |
302 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
303 | # texinfo_show_urls = 'footnote'
304 |
305 | # If true, do not generate a @detailmenu in the "Top" node's menu.
306 | # texinfo_no_detailmenu = False
307 | # -- Options for PDF output --------------------------------------------------
308 |
309 | pdf_documents = [
310 | (master_doc, target_name,
311 | title, author)
312 | ]
313 |
314 | locale_dirs = ['locale/']
315 |
--------------------------------------------------------------------------------
/doc/source/configure-haproxy.rst:
--------------------------------------------------------------------------------
1 | ==============================
2 | Configuring HAProxy (optional)
3 | ==============================
4 |
5 | HAProxy provides load balancing services and SSL termination when hardware
6 | load balancers are not available for high availability architectures deployed
7 | by OpenStack-Ansible. The default HAProxy configuration provides highly-
8 | available load balancing services via keepalived if there is more than one
9 | host in the ``haproxy_hosts`` group.
10 |
11 | .. important::
12 |
13 | Ensure you review the services exposed by HAProxy and limit access
14 | to these services to trusted users and networks only. For more details,
15 | refer to the :dev_docs:`Securing network access to OpenStack services ` section.
16 |
17 | .. note::
18 |
19 | For a successful installation, you require a load balancer. You may
20 | prefer to make use of hardware load balancers instead of HAProxy. If hardware
21 | load balancers are in use, then implement the load balancing configuration for
22 | services prior to executing the deployment.
23 |
24 | To deploy HAProxy within your OpenStack-Ansible environment, define target
25 | hosts to run HAProxy:
26 |
27 | .. code-block:: yaml
28 |
29 | haproxy_hosts:
30 | infra1:
31 | ip: 172.29.236.101
32 | infra2:
33 | ip: 172.29.236.102
34 | infra3:
35 | ip: 172.29.236.103
36 |
37 | There is an example configuration file already provided in
38 | ``/etc/openstack_deploy/conf.d/haproxy.yml.example``. Rename the file to
39 | ``haproxy.yml`` and configure it with the correct target hosts to use HAProxy
40 | in an OpenStack-Ansible deployment.
41 |
42 | Making HAProxy highly-available
43 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
44 |
45 | If multiple hosts are found in the inventory, deploy
46 | HAProxy in a highly-available manner by installing Keepalived.
47 |
48 | To make Keepalived work, edit at least the following variables
49 | in ``user_variables.yml``:
50 |
51 | .. code-block:: yaml
52 |
53 | haproxy_keepalived_external_vip_cidr: 192.168.0.4/25
54 | haproxy_keepalived_internal_vip_cidr: 172.29.236.54/16
55 | haproxy_keepalived_external_interface: br-flat
56 | haproxy_keepalived_internal_interface: br-mgmt
57 |
58 | - ``haproxy_keepalived_internal_interface`` and
59 | ``haproxy_keepalived_external_interface`` represent the interfaces on the
60 | deployed node where the keepalived nodes bind the internal and external
61 | vip. By default, use ``br-mgmt``.
62 |
63 | - On the interface listed above, ``haproxy_keepalived_internal_vip_cidr`` and
64 | ``haproxy_keepalived_external_vip_cidr`` represent the internal and
65 | external (respectively) vips (with their prefix length).
66 |
67 | - Set additional variables to adapt Keepalived in your deployment.
68 | Refer to the ``user_variables.yml`` for more descriptions.
69 |
70 | To always deploy (or upgrade to) the latest stable version of Keepalived.
71 | Edit the ``/etc/openstack_deploy/user_variables.yml``:
72 |
73 | .. code-block:: yaml
74 |
75 | keepalived_use_latest_stable: True
76 |
77 | The HAProxy nodes have group vars applied that define the configuration
78 | of Keepalived. This configuration is stored in
79 | ``group_vars/haproxy_all/keepalived.yml``. It contains the variables
80 | needed for the Keepalived role (master and backup nodes).
81 |
82 | Keepalived pings a public and private IP address to check its status. The
83 | default address is ``193.0.14.129``. To change this default,
84 | set the ``keepalived_external_ping_address`` and
85 | ``keepalived_internal_ping_address`` variables in the
86 | ``user_variables.yml`` file.
87 |
88 | .. note::
89 |
90 | The Keepalived test works with IPv4 addresses only.
91 |
92 | You can adapt Keepalived to your environment by either using our override
93 | mechanisms (per host with userspace ``host_vars``, per group with
94 | userspace``group_vars``, or globally using the userspace
95 | ``user_variables.yml`` file)
96 |
97 | If you wish to deploy multiple HAProxy hosts without Keepalived and
98 | provide your own means for failover between them, edit
99 | ``/etc/openstack_deploy/user_variables.yml`` to skip the deployment
100 | of Keepalived.
101 | To do this, set the following:
102 |
103 | .. code-block:: yaml
104 |
105 | haproxy_use_keepalived: False
106 |
107 | Configuring Keepalived ping checks
108 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
109 |
110 | OpenStack-Ansible configures Keepalived with a check script that pings an
111 | external resource and uses that ping to determine if a node has lost network
112 | connectivity. If the pings fail, Keepalived fails over to another node and
113 | HAProxy serves requests there.
114 |
115 | The destination address, ping count and ping interval are configurable via
116 | Ansible variables in ``/etc/openstack_deploy/user_variables.yml``:
117 |
118 | .. code-block:: yaml
119 |
120 | keepalived_external_ping_address: # Public IP address to ping
121 | keepalived_internal_ping_address: # Private IP address to ping
122 | keepalived_ping_count: # ICMP packets to send (per interval)
123 | keepalived_ping_interval: # How often ICMP packets are sent
124 |
125 | By default, OpenStack-Ansible configures Keepalived to ping one of the root
126 | DNS servers operated by RIPE. You can change this IP address to a different
127 | external address or another address on your internal network.
128 |
129 | If external connectivity fails, it is important that internal services can
130 | still access an HAProxy instance. In a situation, when ping to some external
131 | host fails and internal ping is not separated, all Keepalived instances enter
132 | the fault state despite internal connectivity being still available. Separate
133 | ping check for internal and external connectivity ensures that when one
134 | instance fails the other VIP remains in operation.
135 |
136 | Securing HAProxy communication with SSL certificates
137 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
138 |
139 | The OpenStack-Ansible project provides the ability to secure HAProxy
140 | communications with self-signed or user-provided SSL certificates. By default,
141 | self-signed certificates are used with HAProxy. However, you can
142 | provide your own certificates by using the following Ansible variables:
143 |
144 | .. code-block:: yaml
145 |
146 | haproxy_user_ssl_cert: # Path to certificate
147 | haproxy_user_ssl_key: # Path to private key
148 | haproxy_user_ssl_ca_cert: # Path to CA certificate
149 |
150 | Refer to `Securing services with SSL certificates`_ for more information on
151 | these configuration options and how you can provide your own
152 | certificates and keys to use with HAProxy. User provided certificates should
153 | be folded and formatted at 64 characters long. Single line certificates
154 | will not be accepted by HAProxy and will result in SSL validation failures.
155 | Please have a look here for information on `converting your certificate to
156 | various formats `_.
157 |
158 | Using Certificates from Let’s Encrypt
159 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
160 |
161 | If you want to use Let’s Encrypt `_
162 | you can activate the feature by providing the following configuration in
163 | ``/etc/openstack_deploy/user_variables.yml``. Note that this requires
164 | that ``external_lb_vip_address`` in
165 | ``/etc/openstack_deploy/openstack_user_config.yml`` is set to the
166 | external DNS address.
167 |
168 | The following variables must be set for the HAProxy hosts.
169 |
170 | .. code-block:: yaml
171 |
172 | haproxy_ssl_letsencrypt_enable: True
173 | haproxy_ssl_letsencrypt_email: example@example.com
174 | haproxy_interval: 2000
175 |
176 | The following variables serve as an example for how to configure a
177 | single HAProxy providing SSL termination for a service on the same
178 | host, served from 127.0.0.1:80. An additional HAProxy backend is
179 | configured which will receive the acme-challenge requests when
180 | certificates are renewed.
181 |
182 | .. code-block:: yaml
183 |
184 | haproxy_service_configs:
185 | # the external facing service which serves the apache test site, with a acl for LE requests
186 | - haproxy_service_name: test
187 | haproxy_redirect_http_port: 80 #redirect port 80 to port ssl
188 | haproxy_redirect_scheme: "https if !{ ssl_fc } !{ path_beg /.well-known/acme-challenge/ }" #redirect all non-ssl traffic to ssl except acme-challenge
189 | haproxy_port: 443
190 | haproxy_frontend_acls: #use a frontend ACL specify the backend to use for acme-challenge
191 | letsencrypt-acl:
192 | rule: "path_beg /.well-known/acme-challenge/"
193 | backend_name: letsencrypt
194 | haproxy_ssl: True
195 | haproxy_backend_nodes: #apache is running on locally on 127.0.0.1:80 serving a dummy site
196 | - name: local-test-service
197 | ip_addr: 127.0.0.1
198 | haproxy_balance_type: http
199 | haproxy_backend_port: 80
200 | haproxy_backend_options:
201 | - "httpchk HEAD /" # request to use for health check for the example service
202 |
203 | # an internal only service for acme-challenge whose backend is certbot on the haproxy host
204 | - haproxy_service_name: letsencrypt
205 | haproxy_backend_nodes:
206 | - name: localhost
207 | ip_addr: {{ ansible_host }} #certbot binds to the internal IP
208 | backend_rise: 1 #quick rise and fall time for multinode deployment to succeed
209 | backend_fall: 2
210 | haproxy_bind:
211 | - 127.0.0.1 #bind to 127.0.0.1 as the local internal address will be used by certbot
212 | haproxy_port: 8888 #certbot is configured with http-01-port to be 8888
213 | haproxy_balance_type: http
214 |
215 |
216 | It is possible to use an HA configuration of HAProxy with certificates
217 | initialised and renewed using certbot by setting haproxy_backend_nodes
218 | for the Let’s Encrypt service to include all HAProxy internal addresses.
219 | Each HAProxy instance will be checking for certbot running on its own
220 | node plus each of the others, and direct any incoming acme-challenge
221 | requests to the HAProxy instance which is performing a renewal.
222 |
223 | Domains which will be covered by Let’s Encrypt certificate are defined
224 | with ``haproxy_ssl_letsencrypt_domains`` variable, which can be set to
225 | a list. By default certificate will be issued only for
226 | ``external_lb_vip_address``.
227 |
228 | Another important aspect is defining a list of frontends, for which
229 | issued certificate will be used.
230 | By default, it is goind to be used only for VIPs with type ``external``.
231 | You can control and define type by overriding a variable ``haproxy_vip_binds``.
232 |
233 | It is necessary to configure certbot to bind to the HAProxy node local
234 | internal IP address via the haproxy_ssl_letsencrypt_certbot_bind_address
235 | variable in a H/A setup.
236 |
237 | .. _Securing services with SSL certificates: https://docs.openstack.org/openstack-ansible/latest/user/security/index.html
238 |
239 | Configuring additional services
240 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
241 |
242 | Additional HAProxy service entries can be configured by setting
243 | ``haproxy_extra_services`` in ``/etc/openstack_deploy/user_variables.yml``
244 |
245 | For more information on the service dict syntax, please reference
246 | ``playbooks/vars/configs/haproxy_config.yml``
247 |
248 | An example HTTP service could look like:
249 |
250 | .. code-block:: yaml
251 |
252 | haproxy_extra_services:
253 | - haproxy_service_name: extra-web-service
254 | haproxy_backend_nodes: "{{ groups['service_group'] | default([]) }}"
255 | haproxy_ssl: "{{ haproxy_ssl }}"
256 | haproxy_port: 10000
257 | haproxy_balance_type: http
258 | # If backend connections should be secured with SSL (default False)
259 | haproxy_backend_ssl: True
260 | haproxy_backend_ca: /path/to/ca/cert.pem
261 | # Or to use system CA for validation
262 | # haproxy_backend_ca: True
263 | # Or if certificate validation should be disabled
264 | # haproxy_backend_ca: False
265 |
266 | Additionally, you can specify HAProxy services that are not managed
267 | in the Ansible inventory by manually specifying their hostnames/IP Addresses:
268 |
269 | .. code-block:: yaml
270 |
271 | haproxy_extra_services:
272 | - haproxy_service_name: extra-non-inventory-service
273 | haproxy_backend_nodes:
274 | - name: nonInvHost01
275 | ip_addr: 172.0.1.1
276 | - name: nonInvHost02
277 | ip_addr: 172.0.1.2
278 | - name: nonInvHost03
279 | ip_addr: 172.0.1.3
280 | haproxy_ssl: "{{ haproxy_ssl }}"
281 | haproxy_port: 10001
282 | haproxy_balance_type: http
283 |
284 | Adding additional global VIP addresses
285 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
286 |
287 | In some cases, you might need to add additional internal VIP addresses
288 | to the load balancer front end. You can use the HAProxy role to add
289 | additional VIPs to all front ends by setting them in the
290 | ``extra_lb_vip_addresses`` or ``extra_lb_tls_vip_addresses`` variables.
291 |
292 | The following example shows extra VIP addresses defined in the
293 | ``user_variables.yml`` file:
294 |
295 | .. code-block:: yaml
296 |
297 | extra_lb_vip_addresses:
298 | - 10.0.0.10
299 | - 192.168.0.10
300 |
301 | The following example shows extra VIP addresses with TLS enabled
302 | defined in the ``user_variables.yml`` file:
303 |
304 | .. code-block:: yaml
305 |
306 | extra_lb_tls_vip_addresses:
307 | - 10.0.0.10
308 | - 192.168.0.10
309 |
310 | Controlling HAProxy front-end binding
311 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
312 |
313 | HAProxy frontend can bind either to some specific IP (VIP) address or
314 | ethernet interface. A variable which controls this behaviour is
315 | ``haproxy_vip_binds``. It is used for the service, unless ``haproxy_bind``
316 | is defined on the service level. In that case ``service.haproxy_bind``
317 | has prescedence over ``haproxy_vip_binds``.
318 |
319 | ``haproxy_vip_binds`` is generated by the role from other "convenience"
320 | variables, like
321 | `haproxy_bind_external_lb_vip_address`,
322 | `haproxy_bind_external_lb_vip_interface`,
323 | `haproxy_bind_internal_lb_vip_address` and
324 | `haproxy_bind_internal_lb_vip_interface`.
325 |
326 | Though you still can override ``haproxy_vip_binds`` to fine-control
327 | the binding process of HAProxy instance.
328 |
329 | Overriding the address HAProxy will bind to
330 | -------------------------------------------
331 |
332 | In some cases you may want to override the default of having HAProxy
333 | bind to the addresses specified in ``external_lb_vip_address`` and
334 | ``internal_lb_vip_address``. For example if those are hostnames and you
335 | want HAProxy to bind to IP addresses while preserving the names for TLS-
336 | certificates and endpoint URIs.
337 |
338 | This can be set in the ``user_variables.yml`` file:
339 |
340 | .. code-block:: yaml
341 |
342 | haproxy_bind_external_lb_vip_address: 10.0.0.10
343 | haproxy_bind_internal_lb_vip_address: 192.168.0.10
344 |
345 | Binding HAProxy to interface
346 | ----------------------------
347 |
348 | In some cases it might be more convenient to bind HAProxy to the interface
349 | rather then a specific IP address. For example, this is handy if you decide
350 | to balance load between HAProxy instances using DNS RR, where each HAProxy
351 | will have it's own VIP which will failover to others.
352 |
353 | Binding to the interface can be set by providing following variables
354 | in the ``user_variables.yml`` file:
355 |
356 | .. code-block:: yaml
357 |
358 | haproxy_bind_external_lb_vip_address: "*"
359 | haproxy_bind_internal_lb_vip_address: "*"
360 | haproxy_bind_external_lb_vip_interface: bond0
361 | haproxy_bind_internal_lb_vip_interface: br-mgmt
362 |
363 | Adding Access Control Lists to HAProxy front end
364 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
365 |
366 | Adding ACL rules in HAProxy is easy. You just need to define haproxy_acls and
367 | add the rules in the variable
368 |
369 | Here is an example that shows how to achieve the goal
370 |
371 | .. code-block:: yaml
372 |
373 |
374 | - haproxy_service_name: influxdb-relay
375 | haproxy_acls:
376 | write_queries:
377 | rule: "path_sub -i write"
378 | read_queries:
379 | rule: "path_sub -i query"
380 | backend_name: "influxdb"
381 |
382 | This will add two acl rules ``path_sub -i write`` and ``path_sub -i query`` to
383 | the front end and use the backend specified in the rule. If no backend is specified
384 | it will use a default ``haproxy_service_name`` backend.
385 |
386 | If a frontend service directs to multiple backend services using ACLs, and a
387 | backend service does not require its own corresponding front-end, the
388 | `haproxy_backend_only` option can be specified:
389 |
390 | .. code-block:: yaml
391 |
392 | - haproxy_service_name: influxdb
393 | haproxy_backend_only: true # Directed by the 'influxdb-relay' service above
394 | haproxy_backend_nodes:
395 | - name: influxdb-service
396 | ip_addr: 10.100.10.10
397 |
398 | Adding prometheus metrics to HAProxy
399 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
400 |
401 | Since HAProxy 2.0 it's possible to exposes prometheus metrics.
402 | https://www.haproxy.com/blog/haproxy-exposes-a-prometheus-metrics-endpoint
403 | if you need to create a frontend for it you can use the `haproxy_frontend_only`
404 | option:
405 |
406 | .. code-block:: yaml
407 |
408 | - haproxy_service_name: prometheus-metrics
409 | haproxy_port: 8404
410 | haproxy_bind:
411 | - '127.0.0.1'
412 | haproxy_whitelist_networks: "{{ haproxy_whitelist_networks }}"
413 | haproxy_frontend_only: True
414 | haproxy_frontend_raw:
415 | - 'http-request use-service prometheus-exporter if { path /metrics }'
416 | haproxy_service_enabled: True
417 | haproxy_balance_type: 'http'
418 |
--------------------------------------------------------------------------------
/doc/source/index.rst:
--------------------------------------------------------------------------------
1 | ================================
2 | OpenStack-Ansible HAProxy server
3 | ================================
4 |
5 | .. toctree::
6 | :maxdepth: 2
7 |
8 | configure-haproxy.rst
9 |
10 | This Ansible role installs the HAProxy Load Balancer service.
11 |
12 | To clone or view the source code for this repository, visit the role repository
13 | for `haproxy_server `_.
14 |
15 | Default variables
16 | ~~~~~~~~~~~~~~~~~
17 |
18 | .. literalinclude:: ../../defaults/main.yml
19 | :language: yaml
20 | :start-after: under the License.
21 |
22 | Required variables
23 | ~~~~~~~~~~~~~~~~~~
24 |
25 | None.
26 |
27 | Dependencies
28 | ~~~~~~~~~~~~
29 |
30 | None.
31 |
32 | Example playbook
33 | ~~~~~~~~~~~~~~~~
34 |
35 | .. literalinclude:: ../../examples/playbook.yml
36 | :language: yaml
37 |
--------------------------------------------------------------------------------
/examples/playbook.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Install haproxy
3 | hosts: haproxy
4 | user: root
5 | roles:
6 | - role: haproxy_server
7 | tags:
8 | - haproxy-server
9 | vars:
10 | haproxy_service_configs:
11 | - haproxy_service_name: group_name
12 | haproxy_backend_nodes: "{{ groups['group_name'][0] }}"
13 | haproxy_backup_nodes: "{{ groups['group_name'][1:] }}"
14 | haproxy_port: 80
15 | haproxy_balance_type: http
16 | haproxy_backend_options:
17 | - "forwardfor"
18 | - "httpchk"
19 | - "httplog"
20 | haproxy_backend_arguments:
21 | - "http-check expect string OK"
22 |
--------------------------------------------------------------------------------
/files/haproxy.default:
--------------------------------------------------------------------------------
1 | # Set ENABLED to 1 if you want the init script to start haproxy.
2 | ENABLED=1
3 |
--------------------------------------------------------------------------------
/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2014, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | - name: Regen pem # noqa: no-changed-when
17 | ansible.builtin.shell: >-
18 | cat {{ item_base_path ~ '.crt' }} $(test -f {{ item_base_path ~ '-ca.crt' }} &&
19 | echo {{ item_base_path ~ '-ca.crt' }}) {{ item_base_path ~ '.key' }} > {{ target_base_path ~ '.pem' }}
20 | vars:
21 | item_interface: "{{ item['interface'] | default('') }}"
22 | item_name: "{{ ('interface' in item and item['interface'] is truthy) | ternary(item['address'] ~ '-' ~ item_interface, item['address']) }}"
23 | item_base_path: "{{ haproxy_ssl_temp_path ~ '/haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ item_name }}"
24 | target_base_path: "{{ haproxy_ssl_cert_path ~ '/haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ item_name }}"
25 | with_items: "{{ haproxy_vip_binds }}"
26 | listen:
27 | - haproxy cert installed
28 |
29 | - name: Regenerate maps
30 | vars:
31 | all_changed_results: "{{ (map_create.results + map_delete.results) | select('changed') }}"
32 | ansible.builtin.assemble:
33 | src: "/etc/haproxy/map.conf.d/{{ item }}"
34 | dest: "/etc/haproxy/{{ item }}.map"
35 | mode: "0640"
36 | owner: haproxy
37 | group: haproxy
38 | with_items: "{{ all_changed_results | map(attribute='item') | flatten | selectattr('name', 'defined') | map(attribute='name') | unique }}"
39 |
40 | - name: Regenerate haproxy configuration
41 | ansible.builtin.assemble:
42 | src: "/etc/haproxy/conf.d"
43 | dest: "/etc/haproxy/haproxy.cfg"
44 | validate: /usr/sbin/haproxy -c -f %s
45 | mode: "0640"
46 | owner: haproxy
47 | group: haproxy
48 | tags:
49 | - haproxy-general-config
50 |
51 | - name: Get package facts
52 | ansible.builtin.package_facts:
53 | manager: auto
54 | listen: Restart rsyslog
55 |
56 | - name: Restart rsyslog
57 | ansible.builtin.service:
58 | name: "rsyslog"
59 | state: "restarted"
60 | enabled: true
61 | daemon_reload: true
62 | when:
63 | - "'rsyslog' in ansible_facts.packages"
64 |
65 | - name: Reload haproxy
66 | ansible.builtin.service:
67 | name: "haproxy"
68 | state: "reloaded"
69 | enabled: true
70 | daemon_reload: true
71 | listen:
72 | - Regen pem
73 | - Regenerate maps
74 | - Regenerate haproxy configuration
75 |
--------------------------------------------------------------------------------
/manual-test.rc:
--------------------------------------------------------------------------------
1 | export VIRTUAL_ENV=$(pwd)
2 | export ANSIBLE_HOST_KEY_CHECKING=False
3 | export ANSIBLE_SSH_CONTROL_PATH=/tmp/%%h-%%r
4 |
5 | # TODO (odyssey4me) These are only here as they are non-standard folder
6 | # names for Ansible 1.9.x. We are using the standard folder names for
7 | # Ansible v2.x. We can remove this when we move to Ansible 2.x.
8 | export ANSIBLE_ACTION_PLUGINS=${HOME}/.ansible/plugins/action
9 | export ANSIBLE_CALLBACK_PLUGINS=${HOME}/.ansible/plugins/callback
10 | export ANSIBLE_FILTER_PLUGINS=${HOME}/.ansible/plugins/filter
11 | export ANSIBLE_LOOKUP_PLUGINS=${HOME}/.ansible/plugins/lookup
12 |
13 | # This is required as the default is the current path or a path specified
14 | # in ansible.cfg
15 | export ANSIBLE_LIBRARY=${HOME}/.ansible/plugins/library
16 |
17 | # This is required as the default is '/etc/ansible/roles' or a path
18 | # specified in ansible.cfg
19 | export ANSIBLE_ROLES_PATH=${HOME}/.ansible/roles:$(pwd)/..
20 |
21 | export ANSIBLE_SSH_ARGS="-o ControlMaster=no \
22 | -o UserKnownHostsFile=/dev/null \
23 | -o StrictHostKeyChecking=no \
24 | -o ServerAliveInterval=64 \
25 | -o ServerAliveCountMax=1024 \
26 | -o Compression=no \
27 | -o TCPKeepAlive=yes \
28 | -o VerifyHostKeyDNS=no \
29 | -o ForwardX11=no \
30 | -o ForwardAgent=yes"
31 |
32 | echo "Run manual functional tests by executing the following:"
33 | echo "# ./.tox/functional/bin/ansible-playbook -i tests/inventory tests/test.yml"
34 |
--------------------------------------------------------------------------------
/meta/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2014, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | galaxy_info:
17 | author: rcbops
18 | description: Installation and setup of HAProxy
19 | role_name: haproxy_server
20 | namespace: openstack
21 | company: Rackspace
22 | license: Apache2
23 | min_ansible_version: "2.10"
24 | platforms:
25 | - name: Debian
26 | versions:
27 | - bullseye
28 | - name: Ubuntu
29 | versions:
30 | - focal
31 | - jammy
32 | - name: EL
33 | versions:
34 | - "9"
35 | galaxy_tags:
36 | - cloud
37 | - python
38 | - development
39 | - openstack
40 | dependencies: []
41 |
--------------------------------------------------------------------------------
/meta/openstack-ansible.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2017, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 | # (c) 2017, Jean-Philippe Evrard
17 |
18 | maturity_info:
19 | status: incubated
20 | created_during: newton
21 |
--------------------------------------------------------------------------------
/releasenotes/notes/.placeholder:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/openstack-ansible-haproxy_server/abf058c556f223f2102ab2491f2bb7b9e6f048df/releasenotes/notes/.placeholder
--------------------------------------------------------------------------------
/releasenotes/notes/backend_config_per_host-14cec3ec5f708934.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - HAProxy services that use backend nodes that are not
4 | in the Ansible inventory can now have the ``backend_port``
5 | specified in the list, along with ``name`` or ``ip_addr`` settings.
6 | This allow to have the service bound to different port on different
7 | backend servers.
8 |
--------------------------------------------------------------------------------
/releasenotes/notes/bind_interface-8f7a123d4ab1219a.yaml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | features:
4 | - |
5 | Added variables ``haproxy_bind_external_lb_vip_interface`` and
6 | ``haproxy_bind_internal_lb_vip_interface`` that allows deployer to bind
7 | haproxy on the specific interface only.
8 | - |
9 | Added variable ``haproxy_tls_vip_binds`` that allows to fully override
10 | haproxy bindings, that are generated by the role if some assumptions are
11 | not valid for some scenarios. It is list of mappings, that include address
12 | and interface. Interface key is optional and can be ommited.
13 |
--------------------------------------------------------------------------------
/releasenotes/notes/cert_per_ip-e473f853dbe4047d.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | deprecations:
3 | - |
4 | The following variables have been deprecated and will have no effect:
5 |
6 | * ``haproxy_ssl_cert_path``
7 | * ``haproxy_ssl_key``
8 | * ``haproxy_ssl_pem``
9 | * ``haproxy_ssl_ca_cert``
10 |
11 | These variables were responsible for the path haproxy looked for
12 | certificates on the destination hosts.
13 |
14 | Variables were replaced in favor of ``haproxy_ssl_cert_path`` since the exact
15 | path to certificates will be dynamically set based on the VIP that is used
16 | for the frontend
17 |
--------------------------------------------------------------------------------
/releasenotes/notes/certbot-auto-5ccf2184fb554c90.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | deprecations:
3 | - |
4 | Certbot-auto is deprecated since 2020.
5 | It was removed from haproxy_server role.
6 |
--------------------------------------------------------------------------------
/releasenotes/notes/certbot_ha-83b56aed3f360dba.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Multiple HAProxy nodes can now be deployed in an HA configuration with
5 | keepalived and LetsEncrypt certificates. Certbot can be treated as a
6 | backend service for haproxy and acme-challenge requests from LetsEncrypt
7 | can be directed to whichever HAProxy server is running a certificate
8 | renewal. New variables are defined for frontend ACLs and options
9 | to be passed to Certbot which enable this new feature, but the majority
10 | of the required configuration is done via the existing HAProxy service
11 | setup. An example is provided in the documentation.
12 |
--------------------------------------------------------------------------------
/releasenotes/notes/custom-stick-tables-1c790fe223bb0d5d.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | A new variable ``haproxy_stick_table`` can be defined to apply a
5 | customised stick-table to all backends on the loadbalancer. In addition,
6 | ``haproxy_stick_table`` can be set in each service definition to have a
7 | customised stick-table for a particular backend.
8 | upgrade:
9 | - |
10 | A default stick-table was previously applied to all backends by default
11 | but did not have any specific purpose. This is now removed, and the variable
12 | ``haproxy_stick_table`` should be used to supply a list of config lines
13 | to be applied to each backend to control stick-table functionality.
14 |
--------------------------------------------------------------------------------
/releasenotes/notes/default_backend_override-9840dc75ff9d1a9c.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | A new key ``haproxy_default_backend`` can be defined for each service
5 | configured in the haproxy loadbalancer. Configuring this variable writes
6 | a value for the ``default_backend`` directive into the config for the
7 | service frontend. It can be useful to provide a specific default backend
8 | as a fall-through option when other backends are selected using ACLs,
9 | and to also allow the name of the default backend to be different from
10 | ``haproxy_service_name``.
11 |
--------------------------------------------------------------------------------
/releasenotes/notes/disable-sslv3-303acdcc6b593180.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - SSLv3 is now disabled in the haproxy daemon configuration by default.
4 |
--------------------------------------------------------------------------------
/releasenotes/notes/h2_initial_support-99a3277939942405.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Added new keys ``haproxy_frontend_h2`` and ``haproxy_backend_h2``
5 | per service definition to enable HTTP/2 for a specified service.
6 |
7 | This also add new variables to control default behavoir for
8 | frontends and backends:
9 |
10 | * ``haproxy_frontend_h2: true``
11 | * ``haproxy_backend_h2: false``
12 |
13 | Please mention, that double stack of HTTP/1.1 and HTTP/2 is only available
14 | for TLS protected frontends. In case frontend is just TCP
15 | haproxy_frontend_h2 will be ignored.
16 |
17 | At the same time ``haproxy_backend_h2`` will be respected regardless of
18 | TLS/plain TCP configuration.
19 | upgrade:
20 | - |
21 | HTTP/2 is enabled by default for frontends that are covered with TLS.
22 | You can disable this behaviour by setting ``haproxy_frontend_h2: false``
23 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy-backend-arguments-3b1dca299c7a8296.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - The new option `haproxy_backend_arguments` can be utilized to add
4 | arbitrary options to a HAProxy backend like tcp-check or http-check.
5 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy-bind-override-9562bab32b964de2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - Setting the haproxy_bind list on a service is now used as an override to the
4 | other VIPs defined in the environment. Previously it was being treated as
5 | an append to the other VIPs so there was no path to override the VIP binds
6 | for a service. For example, haproxy_bind could be used to bind a service to
7 | the internal VIP only.
8 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy-frontend-only-haproxy_raw-d55ad3baa8d006f3.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - It is now possible to have a service which only have a frontend.
4 | by using `haproxy_frontend_only` inside your service.
5 | - Add the possibility to have a haproxy_frontend_raw entry to control
6 | haproxy config for the frontend, the entry will be literally copied in
7 | to the service. You can set a list under the key `haproxy_frontend_raw`
8 |
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy-hatop-4d6525a52f93a69e.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | Variable ``haproxy_hatop_downloader`` has been removed, Deployers
5 | supposed to use ``haproxy_hatop_download_url`` override if needed
6 | to install in deployments with limited internet connection.
7 | features:
8 | - |
9 | Added new variable ``haproxy_hatop_install``, that allows to conditionally
10 | enable or disable hatop installation.
11 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy-maps-787084d7f161c27e.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | A new key `haproxy_map_entries` is now able to be configured for each
5 | haproxy service definition to allow arbitrary entries to be placed in
6 | any number of haproxy map files which may then be referenced in other
7 | directives in the haproxy config file such as ``use_backend`` or
8 | ``http-request``. The complete map files are constructed from the
9 | fragments defined across all the service definitions and are assembled
10 | into a complete map file in alphanumeric sort order, or optionally with
11 | a user defined ordering.
12 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy-selinux-all-ports-4094eed48f2bfbca.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - The haproxy daemon is now able to bind to any port on CentOS 7. The
4 | ``haproxy_connect_any`` SELinux boolean is now set to ``on``.
5 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy_allowlist-95aa9b911baeacd9.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | HAProxy ``haproxy_whitelist_networks`` key inside
5 | ``haproxy_service_configs`` dictionary has been replaced with
6 | ``haproxy_allowlist_networks``.
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy_custom_errorfiles-500674edcaa6cbb6.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Added support for defining custom error files using haproxy_errorfiles.
5 | These files can be distributed alongside haproxy_static_files_extra.
6 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy_frontend_raw-0811d5d445a66b41.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - |
4 | Fixed inconsistency in ``haproxy_frontend_raw`` key naming between
5 | documentation and service template. Previously, template generation
6 | was expecting ``haproxy_raw`` instead of the ``haproxy_frontend_raw``.
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy_letsencrypt-4a13c7911a20b993.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | There's no need in providing neither `http-01-address` nor `http-01-port`
5 | options with `haproxy_ssl_letsencrypt_setup_extra_params`, as they are now
6 | configured with corresponding variables
7 | `haproxy_ssl_letsencrypt_certbot_bind_address` and
8 | `haproxy_ssl_letsencrypt_certbot_backend_port`
9 | features:
10 | - |
11 | Added variable `haproxy_ssl_letsencrypt_certbot_challenge` which is default
12 | to `http-01`. As for now really tested in only `http-01` but we keep door
13 | open for adding support for more challanges, like `dns-01`. For `http-01`
14 | all required arguments are passed, but oth other challanges you might want
15 | to use `haproxy_ssl_letsencrypt_setup_extra_params` to pass missing
16 | arguments.
17 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy_pki_create_certificates-28dd48424855f463.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | ``haproxy_pki_create_certificates`` was implemented. It allows users to
5 | explicitly disable certificates generation with PKI role but keep using
6 | it for certificates distribution.
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy_rise_fall-64ba2e6d7e206973.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fixes:
3 | - |
4 | Variables ``haproxy_fall`` and ``haproxy_rise`` are now respected again
5 | and will be used for defining amount of checks before haproxy will mark
6 | backend as UP or DOWN. Keys ``backend_rise`` and ``haproxy_fall`` that are
7 | set inside service definition are still respected and will have
8 | prescedence over global ones.
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy_ssl_path-7130354314aee961.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - HAProxy services can now override the path of the certificate with
4 | ``haproxy_ssl_path`` if set under the service definition.
5 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy_sysctl_location-e18310fd96597a6f.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Allow the definition of a custom sysctl config path through
5 | `openstack_sysctl_file` and/or `haproxy_sysctl_file`.
6 | Defaults to `/etc/sysctl.conf` to retain backwards compatibility.
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/haproxy_tuning_params_released-45eb40104747561a.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | If you have defined ``haproxy_tuning_params`` in your deployment, make sure
5 | that before upgrade all keys are valid haproxy options. For example,
6 | instead of ``chksize: 16384`` you should set ``tune.chksize: 16384``.
7 | Otherwise invalid config will be generated and haproxy will fail on
8 | startup.
9 | No upgrade scripts are provided for this change as well as no backwards
10 | compatability.
11 | other:
12 | - |
13 | Restriction on parameters that can be passed to ``haproxy_tuning_params``
14 | has been released. This means, that any tuning parameter can be passed in
15 | key/value format.
16 | fixes:
17 | - |
18 | By default we increase ``tune.maxrewrite`` as otherwise while using CSP
19 | headers, their size could exceed allowed buffer.
20 | Also deployers can override this value if needed.
21 |
--------------------------------------------------------------------------------
/releasenotes/notes/implement_tuning_params-e627c774c0d0c9d2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - Haproxy-server role allows to set up tunable parameters.
4 | For doing that it is necessary to set up a dictionary of options in the
5 | config files, mentioning those which have to be changed (defaults for the
6 | remaining ones are programmed in the template). Also "maxconn" global option
7 | made to be tunable.
8 | upgrade:
9 | - The ``haproxy_bufsize`` variable has been removed and made a part of the
10 | ``haproxy_tuning_params`` dictionary.
11 |
--------------------------------------------------------------------------------
/releasenotes/notes/letsencrypt-ssl-certification-129a80cb88d8e6ff.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | If Horizon dashboard of OSA installation has a public FQDN, is it
5 | now possible to use LetsEncrypt certification service. Certificate
6 | will be generated within HAProxy installation and a cron entry to
7 | renew the certificate daily will be setup.
8 | Note that there is no certificate distribution implementation at
9 | this time, so this will only work for a single haproxy-server
10 | environment.
11 |
--------------------------------------------------------------------------------
/releasenotes/notes/non_inventory_hosts-c0fa4c185a01e78b.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - HAProxy services that use backend nodes that are not
4 | in the Ansible inventory can now be specified manually
5 | by setting ``haproxy_backend_nodes`` to a list of
6 | ``name`` and ``ip_addr`` settings.
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/package-list-name-changes-a26d94a44c24de2f.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - The variable ``haproxy_pre_packages`` has been renamed to
4 | ``haproxy_required_distro_packages``.
5 | - The variable ``haproxy_packages`` has been renamed to
6 | ``haproxy_distro_packages``.
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/pki-temp-certs-path-d63091df0234df2e.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | If directory is defined instead of certificate files, haproxy will attempt
5 | to treat all files within as a pem bundled certs. And will fail its
6 | configuration test.
7 | To avoid this a new variable haproxy_ssl_temp_path were introduced. When it
8 | is defined certificates from the pki being put into that directory and then
9 | combined into pem in the correct directory.
10 |
11 | Such an approach allows us to put additional certificates to the directory
12 | outside of the haproxy_server role and keep the directory clean. This also
13 | eliminates the need to list all additional custom certificates and sum them
14 | with the ones calculate by this role.
15 |
16 | Additionally added a cleanup/move of the certs if haproxy_ssl_temp_path set
17 | to be different from haproxy_ssl_cert_path which allows a transition from
18 | old setup.
19 |
--------------------------------------------------------------------------------
/releasenotes/notes/refresh-interval-configuration-option-884d64aa259ecc3c.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Deployers can set a refresh interval for haproxy's stats page by setting
5 | the ``haproxy_stats_refresh_interval`` variable. The default value is
6 | ``60``, which causes haproxy to refresh the stats page every 60 seconds.
7 |
--------------------------------------------------------------------------------
/releasenotes/notes/remove-haproxy-repo-vars-051a47bbfaf6d1da.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | upgrade:
3 | - |
4 | The following variables have been removed from the ``haproxy_server`` role
5 | as they are no longer necessary or used.
6 | - haproxy_repo
7 | - haproxy_gpg_keys
8 | - haproxy_required_distro_packages
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/rename_haproxy_vip_binds-dda8197aaf607b53.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | deprecations:
3 | - |
4 | Variable ``haproxy_tls_vip_binds`` has been renamed to
5 | ``haproxy_vip_binds`` to better reflect variable purpose.
6 | Old variable name is still respected but it's usage is
7 | descouraged and old naming will be removed in the future.
8 |
--------------------------------------------------------------------------------
/releasenotes/notes/separated-haproxy-config-b38d200ee0baaeac.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | deprecations:
3 | - |
4 | ``haproxy_service_configs`` format was simplified.
5 | Now it's just a list of dicts. Usage of ``service`` key
6 | in ``haproxy_service_configs`` elements is deprecated and will be
7 | removed in 2023.2 release.
8 |
9 |
--------------------------------------------------------------------------------
/releasenotes/notes/stick-table-9ef4bd94a4a000b3.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | Added new variable haproxy_stick_table_enabled to haproxy_service_configs,
5 | that allows you to conditionally enable or disable the default stick-table.
6 |
--------------------------------------------------------------------------------
/releasenotes/notes/tls12-only-a22d5f3f8198617f.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | security:
3 | - |
4 | The default TLS version has been set to force-tlsv12. This only allows
5 | version 1.2 of the protocol to be used when terminating or creating TLS
6 | connections. You can change the value with the haproxy_ssl_bind_options
7 | variable.
8 |
--------------------------------------------------------------------------------
/releasenotes/notes/tls_variables-91160d4e38085de4.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | features:
3 | - |
4 | The HAProxy role now supports TLS v1.3 by default, alongside TLS v1.2.
5 | deprecations:
6 | - |
7 | The variable 'haproxy_ssl_cipher_suite' is deprecated in favour of
8 | 'haproxy_ssl_cipher_suite_tls12' which will continue to manage
9 | configuration of ciphers for TLS v1.2 and earlier.
10 |
--------------------------------------------------------------------------------
/releasenotes/source/_static/.placeholder:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/openstack-ansible-haproxy_server/abf058c556f223f2102ab2491f2bb7b9e6f048df/releasenotes/source/_static/.placeholder
--------------------------------------------------------------------------------
/releasenotes/source/_templates/.placeholder:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/openstack-ansible-haproxy_server/abf058c556f223f2102ab2491f2bb7b9e6f048df/releasenotes/source/_templates/.placeholder
--------------------------------------------------------------------------------
/releasenotes/source/conf.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12 | # implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | # This file is execfile()d with the current directory set to its
17 | # containing dir.
18 | #
19 | # Note that not all possible configuration values are present in this
20 | # autogenerated file.
21 | #
22 | # All configuration values have a default; values that are commented out
23 | # serve to show the default.
24 |
25 | # If extensions (or modules to document with autodoc) are in another directory,
26 | # add these directories to sys.path here. If the directory is relative to the
27 | # documentation root, use os.path.abspath to make it absolute, like shown here.
28 | # sys.path.insert(0, os.path.abspath('.'))
29 |
30 | # -- General configuration ------------------------------------------------
31 |
32 | # If your documentation needs a minimal Sphinx version, state it here.
33 | # needs_sphinx = '1.0'
34 |
35 | # Add any Sphinx extension module names here, as strings. They can be
36 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
37 | # ones.
38 | extensions = [
39 | 'openstackdocstheme',
40 | 'reno.sphinxext',
41 | ]
42 |
43 | # Add any paths that contain templates here, relative to this directory.
44 | templates_path = ['_templates']
45 |
46 | # The suffix of source filenames.
47 | source_suffix = '.rst'
48 |
49 | # The encoding of source files.
50 | # source_encoding = 'utf-8-sig'
51 |
52 | # The master toctree document.
53 | master_doc = 'index'
54 |
55 | # General information about the project.
56 | author = 'OpenStack-Ansible Contributors'
57 | category = 'Miscellaneous'
58 | copyright = '2014-2016, OpenStack-Ansible Contributors'
59 | description = 'OpenStack-Ansible deploys OpenStack environments using Ansible.'
60 | project = 'OpenStack-Ansible'
61 | role_name = 'haproxy_server'
62 | target_name = 'openstack-ansible-' + role_name
63 | title = 'OpenStack-Ansible Release Notes: ' + role_name + 'role'
64 |
65 | # Release notes do not need a version number in the title,
66 | # they cover multiple versions.
67 | # The full version, including alpha/beta/rc tags.
68 | release = ''
69 | # The short X.Y version.
70 | version = ''
71 |
72 | # openstackdocstheme options
73 | openstackdocs_repo_name = 'openstack/' + target_name
74 | openstackdocs_bug_project = project.lower()
75 | openstackdocs_bug_tag = ''
76 |
77 | # The language for content autogenerated by Sphinx. Refer to documentation
78 | # for a list of supported languages.
79 | # language = None
80 |
81 | # There are two options for replacing |today|: either, you set today to some
82 | # non-false value, then it is used:
83 | # today = ''
84 | # Else, today_fmt is used as the format for a strftime call.
85 | # today_fmt = '%B %d, %Y'
86 |
87 | # List of patterns, relative to source directory, that match files and
88 | # directories to ignore when looking for source files.
89 | exclude_patterns = []
90 |
91 | # The reST default role (used for this markup: `text`) to use for all
92 | # documents.
93 | # default_role = None
94 |
95 | # If true, '()' will be appended to :func: etc. cross-reference text.
96 | # add_function_parentheses = True
97 |
98 | # If true, the current module name will be prepended to all description
99 | # unit titles (such as .. function::).
100 | # add_module_names = True
101 |
102 | # If true, sectionauthor and moduleauthor directives will be shown in the
103 | # output. They are ignored by default.
104 | # show_authors = False
105 |
106 | # The name of the Pygments (syntax highlighting) style to use.
107 | pygments_style = 'native'
108 |
109 | # A list of ignored prefixes for module index sorting.
110 | # modindex_common_prefix = []
111 |
112 | # If true, keep warnings as "system message" paragraphs in the built documents.
113 | # keep_warnings = False
114 |
115 |
116 | # -- Options for HTML output ----------------------------------------------
117 |
118 | # The theme to use for HTML and HTML Help pages. See the documentation for
119 | # a list of builtin themes.
120 | html_theme = 'openstackdocs'
121 |
122 | # Theme options are theme-specific and customize the look and feel of a theme
123 | # further. For a list of options available for each theme, see the
124 | # documentation.
125 | # html_theme_options = {}
126 |
127 | # Add any paths that contain custom themes here, relative to this directory.
128 | # html_theme_path = []
129 |
130 | # The name for this set of Sphinx documents. If None, it defaults to
131 | # " v documentation".
132 | # html_title = None
133 |
134 | # A shorter title for the navigation bar. Default is the same as html_title.
135 | # html_short_title = None
136 |
137 | # The name of an image file (relative to this directory) to place at the top
138 | # of the sidebar.
139 | # html_logo = None
140 |
141 | # The name of an image file (within the static path) to use as favicon of the
142 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
143 | # pixels large.
144 | # html_favicon = None
145 |
146 | # Add any paths that contain custom static files (such as style sheets) here,
147 | # relative to this directory. They are copied after the builtin static files,
148 | # so a file named "default.css" will overwrite the builtin "default.css".
149 | html_static_path = ['_static']
150 |
151 | # Add any extra paths that contain custom files (such as robots.txt or
152 | # .htaccess) here, relative to this directory. These files are copied
153 | # directly to the root of the documentation.
154 | # html_extra_path = []
155 |
156 | # If true, SmartyPants will be used to convert quotes and dashes to
157 | # typographically correct entities.
158 | # html_use_smartypants = True
159 |
160 | # Custom sidebar templates, maps document names to template names.
161 | # html_sidebars = {}
162 |
163 | # Additional templates that should be rendered to pages, maps page names to
164 | # template names.
165 | # html_additional_pages = {}
166 |
167 | # If false, no module index is generated.
168 | # html_domain_indices = True
169 |
170 | # If false, no index is generated.
171 | # html_use_index = True
172 |
173 | # If true, the index is split into individual pages for each letter.
174 | # html_split_index = False
175 |
176 | # If true, links to the reST sources are added to the pages.
177 | # html_show_sourcelink = True
178 |
179 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
180 | # html_show_sphinx = True
181 |
182 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
183 | # html_show_copyright = True
184 |
185 | # If true, an OpenSearch description file will be output, and all pages will
186 | # contain a tag referring to it. The value of this option must be the
187 | # base URL from which the finished HTML is served.
188 | # html_use_opensearch = ''
189 |
190 | # This is the file name suffix for HTML files (e.g. ".xhtml").
191 | # html_file_suffix = None
192 |
193 | # Output file base name for HTML help builder.
194 | htmlhelp_basename = target_name + '-docs'
195 |
196 |
197 | # -- Options for LaTeX output ---------------------------------------------
198 |
199 | latex_elements = {
200 | # The paper size ('letterpaper' or 'a4paper').
201 | # 'papersize': 'letterpaper',
202 |
203 | # The font size ('10pt', '11pt' or '12pt').
204 | # 'pointsize': '10pt',
205 |
206 | # Additional stuff for the LaTeX preamble.
207 | # 'preamble': '',
208 | }
209 |
210 | # Grouping the document tree into LaTeX files. List of tuples
211 | # (source start file, target name, title,
212 | # author, documentclass [howto, manual, or own class]).
213 | latex_documents = [
214 | (master_doc, target_name + '.tex',
215 | title, author, 'manual'),
216 | ]
217 |
218 | # The name of an image file (relative to this directory) to place at the top of
219 | # the title page.
220 | # latex_logo = None
221 |
222 | # For "manual" documents, if this is true, then toplevel headings are parts,
223 | # not chapters.
224 | # latex_use_parts = False
225 |
226 | # If true, show page references after internal links.
227 | # latex_show_pagerefs = False
228 |
229 | # If true, show URL addresses after external links.
230 | # latex_show_urls = False
231 |
232 | # Documents to append as an appendix to all manuals.
233 | # latex_appendices = []
234 |
235 | # If false, no module index is generated.
236 | # latex_domain_indices = True
237 |
238 |
239 | # -- Options for manual page output ---------------------------------------
240 |
241 | # One entry per manual page. List of tuples
242 | # (source start file, name, description, authors, manual section).
243 | man_pages = [
244 | (master_doc, target_name,
245 | title, [author], 1)
246 | ]
247 |
248 | # If true, show URL addresses after external links.
249 | # man_show_urls = False
250 |
251 |
252 | # -- Options for Texinfo output -------------------------------------------
253 |
254 | # Grouping the document tree into Texinfo files. List of tuples
255 | # (source start file, target name, title, author,
256 | # dir menu entry, description, category)
257 | texinfo_documents = [
258 | (master_doc, target_name,
259 | title, author, project,
260 | description, category),
261 | ]
262 |
263 | # Documents to append as an appendix to all manuals.
264 | # texinfo_appendices = []
265 |
266 | # If false, no module index is generated.
267 | # texinfo_domain_indices = True
268 |
269 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
270 | # texinfo_show_urls = 'footnote'
271 |
272 | # If true, do not generate a @detailmenu in the "Top" node's menu.
273 | # texinfo_no_detailmenu = False
274 |
275 | # -- Options for Internationalization output ------------------------------
276 | locale_dirs = ['locale/']
277 |
--------------------------------------------------------------------------------
/releasenotes/source/index.rst:
--------------------------------------------------------------------------------
1 | ================================
2 | OpenStack-Ansible Release Notes
3 | ================================
4 |
5 | .. toctree::
6 | :maxdepth: 1
7 |
8 | unreleased
9 | zed
10 | victoria
11 | ussuri
12 | train
13 | stein
14 | rocky
15 | queens
16 | pike
17 | ocata
18 | newton
19 |
--------------------------------------------------------------------------------
/releasenotes/source/newton.rst:
--------------------------------------------------------------------------------
1 | ===================================
2 | Newton Series Release Notes
3 | ===================================
4 |
5 | .. release-notes::
6 | :branch: origin/stable/newton
7 |
--------------------------------------------------------------------------------
/releasenotes/source/ocata.rst:
--------------------------------------------------------------------------------
1 | ===================================
2 | Ocata Series Release Notes
3 | ===================================
4 |
5 | .. release-notes::
6 | :branch: origin/stable/ocata
7 |
--------------------------------------------------------------------------------
/releasenotes/source/pike.rst:
--------------------------------------------------------------------------------
1 | ===================================
2 | Pike Series Release Notes
3 | ===================================
4 |
5 | .. release-notes::
6 | :branch: stable/pike
7 |
--------------------------------------------------------------------------------
/releasenotes/source/queens.rst:
--------------------------------------------------------------------------------
1 | ===================================
2 | Queens Series Release Notes
3 | ===================================
4 |
5 | .. release-notes::
6 | :branch: stable/queens
7 |
--------------------------------------------------------------------------------
/releasenotes/source/rocky.rst:
--------------------------------------------------------------------------------
1 | ===================================
2 | Rocky Series Release Notes
3 | ===================================
4 |
5 | .. release-notes::
6 | :branch: stable/rocky
7 |
--------------------------------------------------------------------------------
/releasenotes/source/stein.rst:
--------------------------------------------------------------------------------
1 | ===================================
2 | Stein Series Release Notes
3 | ===================================
4 |
5 | .. release-notes::
6 | :branch: stable/stein
7 |
--------------------------------------------------------------------------------
/releasenotes/source/train.rst:
--------------------------------------------------------------------------------
1 | ==========================
2 | Train Series Release Notes
3 | ==========================
4 |
5 | .. release-notes::
6 | :branch: stable/train
7 |
--------------------------------------------------------------------------------
/releasenotes/source/unreleased.rst:
--------------------------------------------------------------------------------
1 | ==============================
2 | Current Series Release Notes
3 | ==============================
4 |
5 | .. release-notes::
6 |
--------------------------------------------------------------------------------
/releasenotes/source/ussuri.rst:
--------------------------------------------------------------------------------
1 | ===========================
2 | Ussuri Series Release Notes
3 | ===========================
4 |
5 | .. release-notes::
6 | :branch: stable/ussuri
7 |
--------------------------------------------------------------------------------
/releasenotes/source/victoria.rst:
--------------------------------------------------------------------------------
1 | =============================
2 | Victoria Series Release Notes
3 | =============================
4 |
5 | .. release-notes::
6 | :branch: unmaintained/victoria
7 |
--------------------------------------------------------------------------------
/releasenotes/source/zed.rst:
--------------------------------------------------------------------------------
1 | ========================
2 | Zed Series Release Notes
3 | ========================
4 |
5 | .. release-notes::
6 | :branch: unmaintained/zed
7 |
--------------------------------------------------------------------------------
/run_tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # Copyright 2015, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | # PURPOSE:
17 | # This script clones the openstack-ansible-tests repository to the
18 | # tests/common folder in order to be able to re-use test components
19 | # for role testing. This is intended to be the thinnest possible
20 | # shim for test execution outside of OpenStack CI.
21 |
22 | # WARNING:
23 | # This file is maintained in the openstack-ansible-tests repository.
24 | # https://opendev.org/openstack/openstack-ansible-tests/src/run_tests.sh
25 | # If you need to modify this file, update the one in the openstack-ansible-tests
26 | # repository and then update this file as well. The purpose of this file is to
27 | # prepare the host and then execute all the tox tests.
28 | #
29 |
30 | ## Shell Opts ----------------------------------------------------------------
31 | set -xeu
32 |
33 | ## Vars ----------------------------------------------------------------------
34 |
35 | WORKING_DIR="$(readlink -f $(dirname $0))"
36 | OSA_PROJECT_NAME="$(sed -n 's|^project=openstack/\(.*\).git$|\1|p' $(pwd)/.gitreview)"
37 |
38 | COMMON_TESTS_PATH="${WORKING_DIR}/tests/common"
39 | TESTING_HOME=${TESTING_HOME:-$HOME}
40 | ZUUL_TESTS_CLONE_LOCATION="/home/zuul/src/opendev.org/openstack/openstack-ansible-tests"
41 |
42 | # Use .gitreview as the key to determine the appropriate
43 | # branch to clone for tests.
44 | TESTING_BRANCH=$(awk -F'=' '/defaultbranch/ {print $2}' "${WORKING_DIR}/.gitreview")
45 | if [[ "${TESTING_BRANCH}" == "" ]]; then
46 | TESTING_BRANCH="master"
47 | fi
48 |
49 | ## Main ----------------------------------------------------------------------
50 |
51 | # Source distribution information
52 | source /etc/os-release || source /usr/lib/os-release
53 |
54 | # Figure out the appropriate package install command
55 | case ${ID,,} in
56 | centos|rhel|fedora|rocky) pkg_mgr_cmd="dnf install -y" ;;
57 | ubuntu|debian) pkg_mgr_cmd="apt-get install -y" ;;
58 | *) echo "unsupported distribution: ${ID,,}"; exit 1 ;;
59 | esac
60 |
61 | # Install git so that we can clone the tests repo if git is not available
62 | which git &>/dev/null || eval sudo "${pkg_mgr_cmd}" git
63 |
64 | # Clone the tests repo for access to the common test script
65 | if [[ ! -d "${COMMON_TESTS_PATH}" ]]; then
66 | # The tests repo doesn't need a clone, we can just
67 | # symlink it.
68 | if [[ "${OSA_PROJECT_NAME}" == "openstack-ansible-tests" ]]; then
69 | ln -s "${WORKING_DIR}" "${COMMON_TESTS_PATH}"
70 |
71 | # In zuul v3 any dependent repository is placed into
72 | # /home/zuul/src/opendev.org, so we check to see
73 | # if there is a tests checkout there already. If so, we
74 | # symlink that and use it.
75 | elif [[ -d "${ZUUL_TESTS_CLONE_LOCATION}" ]]; then
76 | ln -s "${ZUUL_TESTS_CLONE_LOCATION}" "${COMMON_TESTS_PATH}"
77 |
78 | # Otherwise we're clearly not in zuul or using a previously setup
79 | # repo in some way, so just clone it from upstream.
80 | else
81 | git clone -b "${TESTING_BRANCH}" \
82 | https://opendev.org/openstack/openstack-ansible-tests \
83 | "${COMMON_TESTS_PATH}"
84 | fi
85 | fi
86 |
87 | # Execute the common test script
88 | source tests/common/run_tests_common.sh
89 |
--------------------------------------------------------------------------------
/tasks/haproxy_install.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2014, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | - name: Install HAProxy Packages
17 | ansible.builtin.package:
18 | name: "{{ haproxy_distro_packages }}"
19 | state: "{{ haproxy_package_state }}"
20 | update_cache: "{{ (ansible_facts['pkg_mgr'] == 'apt') | ternary('yes', omit) }}"
21 | cache_valid_time: "{{ (ansible_facts['pkg_mgr'] == 'apt') | ternary(cache_timeout, omit) }}"
22 | register: install_packages
23 | until: install_packages is success
24 | retries: 5
25 | delay: 2
26 |
27 | - name: Install HATop Utility
28 | block:
29 | - name: Ensure haproxy_hatop_download_path exists on haproxy
30 | ansible.builtin.file:
31 | path: "{{ haproxy_hatop_download_path }}/{{ haproxy_hatop_download_url | basename | replace('.tar.gz', '') }}"
32 | state: directory
33 | mode: "0755"
34 |
35 | - name: Download hatop package
36 | ansible.builtin.get_url:
37 | url: "{{ haproxy_hatop_download_url }}"
38 | dest: "{{ haproxy_hatop_download_path }}/{{ haproxy_hatop_download_url | basename }}"
39 | validate_certs: "{{ haproxy_hatop_download_validate_certs }}"
40 | checksum: "{{ haproxy_hatop_download_checksum }}"
41 | mode: "0644"
42 | register: fetch_url
43 | until: fetch_url is success
44 | retries: 3
45 | delay: 10
46 |
47 | - name: Unarchive HATop
48 | ansible.builtin.unarchive:
49 | src: "{{ haproxy_hatop_download_path }}/{{ haproxy_hatop_download_url | basename }}"
50 | dest: "{{ haproxy_hatop_download_path }}/{{ haproxy_hatop_download_url | basename | replace('.tar.gz', '') }}"
51 | remote_src: true
52 | extra_opts:
53 | - --strip-components=1
54 |
55 | - name: Copy HATop binary
56 | ansible.builtin.copy:
57 | src: "{{ haproxy_hatop_download_path }}/{{ haproxy_hatop_download_url | basename | replace('.tar.gz', '') }}/bin/hatop"
58 | dest: /usr/local/bin/hatop
59 | mode: "0755"
60 | remote_src: true
61 | when: haproxy_hatop_install | bool
62 |
--------------------------------------------------------------------------------
/tasks/haproxy_post_install.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2014, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | - name: Make haproxy bindable on non local addresses
17 | ansible.posix.sysctl:
18 | name: "{{ item }}"
19 | value: 1
20 | sysctl_set: true
21 | sysctl_file: "{{ haproxy_sysctl_file }}"
22 | state: present
23 | when: haproxy_bind_on_non_local | bool
24 | with_items:
25 | - "net.ipv4.ip_nonlocal_bind"
26 | - "net.ipv6.ip_nonlocal_bind"
27 | tags:
28 | - haproxy-non-local-bind-config
29 |
30 | # NOTE (noonedeadpunk) Debian/Ubuntu haproxy packages configure rsyslog
31 | # to handle log collection and log file rotation. This is not needed since
32 | # journald is used for this purpose
33 | - name: Delete rsyslog and logrotate configs
34 | ansible.builtin.file:
35 | path: "{{ item }}"
36 | state: absent
37 | with_items:
38 | - /etc/rsyslog.d/49-haproxy.conf
39 | - /etc/logrotate.d/haproxy
40 | - /etc/rsyslog.d/10-haproxy-local-logging.conf
41 | notify: Restart rsyslog
42 | tags:
43 | - haproxy-logging-config
44 |
45 | - name: Drop base haproxy config
46 | ansible.builtin.template:
47 | src: "haproxy.cfg.j2"
48 | dest: "/etc/haproxy/conf.d/00-haproxy"
49 | mode: "0640"
50 | owner: haproxy
51 | group: haproxy
52 | notify: Regenerate haproxy configuration
53 | tags:
54 | - haproxy-base-config
55 |
56 | - name: Including haproxy_service_config tasks
57 | ansible.builtin.include_tasks: haproxy_service_config.yml
58 | args:
59 | apply:
60 | tags:
61 | - haproxy-service-config
62 | tags:
63 | - haproxy-service-config
64 |
65 | - name: Create log directory if it does not exist
66 | ansible.builtin.file:
67 | path: "{{ haproxy_log_mount_point | dirname }}"
68 | state: directory
69 | mode: "0755"
70 | owner: "haproxy"
71 | group: "haproxy"
72 |
73 | # NOTE(jrosser) The next task fails on Centos without this,
74 | # an empty directory rather than a file is made and the bind mount fails
75 | - name: Ensure empty file is availble to bind mount log socket
76 | ansible.builtin.file:
77 | state: touch
78 | path: "{{ haproxy_log_mount_point }}"
79 | access_time: preserve
80 | modification_time: preserve
81 | mode: "0666"
82 |
83 | - name: Make log socket available to chrooted filesystem
84 | ansible.posix.mount:
85 | src: "{{ haproxy_log_socket }}"
86 | path: "{{ haproxy_log_mount_point }}"
87 | opts: bind
88 | state: mounted
89 | fstype: none
90 |
91 | - name: Prevent SELinux from preventing haproxy from binding to arbitrary ports
92 | ansible.posix.seboolean:
93 | name: haproxy_connect_any
94 | state: true
95 | persistent: true
96 | tags:
97 | - haproxy-service-config
98 | notify:
99 | - Reload haproxy
100 | when:
101 | - ansible_facts['selinux']['status'] == "enabled"
102 |
--------------------------------------------------------------------------------
/tasks/haproxy_pre_install.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2015, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | # NOTE(cloudnull):
17 | # While the haproxy distro packages provide for an haproxy
18 | # group this group is being created upfront to support
19 | # log aggregation links as well as ensure common user
20 | # functionality across various distros that we support.
21 | - name: Create the haproxy system group
22 | ansible.builtin.group:
23 | name: "haproxy"
24 | state: "present"
25 | system: "yes"
26 | tags:
27 | - haproxy-group
28 |
29 | # NOTE(cloudnull):
30 | # While the haproxy distro packages provide for an haproxy
31 | # user this user is being created upfront to support
32 | # log aggregation links as well as ensure common user
33 | # functionality across various distros that we support.
34 | - name: Create the haproxy system user
35 | ansible.builtin.user:
36 | name: "haproxy"
37 | group: "haproxy"
38 | comment: "haproxy user"
39 | shell: "/bin/false"
40 | system: "yes"
41 | createhome: "yes"
42 | home: "/var/lib/haproxy"
43 | tags:
44 | - haproxy-user
45 |
46 | - name: Create haproxy conf.d dir
47 | ansible.builtin.file:
48 | path: "{{ item }}"
49 | state: directory
50 | mode: "0755"
51 | owner: haproxy
52 | group: haproxy
53 | with_items:
54 | - /etc/haproxy/conf.d
55 | - "{{ haproxy_ssl_cert_path }}"
56 | - "{{ haproxy_ssl_temp_path }}"
57 |
58 | - name: Cleanup haproxy_ssl_cert_path if temp_path is used
59 | when: "haproxy_ssl_cert_path != haproxy_ssl_temp_path"
60 | block:
61 | - name: Find crt and key files in the cert_path
62 | ansible.builtin.find:
63 | paths: "{{ haproxy_ssl_cert_path }}"
64 | patterns: '*.crt,*.key'
65 | register: old_certs
66 |
67 | - name: Copy cert files to the temp_path
68 | vars:
69 | filename: "{{ item | basename }}"
70 | ansible.builtin.copy:
71 | remote_src: true
72 | src: "{{ item }}"
73 | dest: "{{ [haproxy_ssl_temp_path, filename] | path_join }}"
74 | mode: "0644"
75 | loop: "{{ old_certs['files'] | map(attribute='path') }}"
76 |
77 | - name: Remove file from the old place
78 | ansible.builtin.file:
79 | path: "{{ item }}"
80 | state: absent
81 | loop: "{{ old_certs['files'] | map(attribute='path') }}"
82 |
83 | - name: Copy static files
84 | ansible.builtin.copy:
85 | content: "{{ item.content }}"
86 | dest: "{{ item.dest }}"
87 | mode: "0644"
88 | owner: haproxy
89 | group: haproxy
90 | when:
91 | - (item.condition | default(True))
92 | loop: "{{ haproxy_static_files }}"
93 | no_log: true
94 |
--------------------------------------------------------------------------------
/tasks/haproxy_service_config.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2014, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | # NOTE(damiandabrowski): Deprecated haproxy_service_configs format
17 | # conversion will be removed in 2024.1.
18 | - name: Define blank _haproxy_service_configs_simplified variable
19 | ansible.builtin.set_fact:
20 | _haproxy_service_configs_simplified: []
21 |
22 | - name: Append services to _haproxy_service_configs_simplified list
23 | ansible.builtin.set_fact:
24 | _haproxy_service_configs_simplified: "{{ _haproxy_service_configs_simplified + [(item.service is defined) | ternary(item.service, item)] }}"
25 | loop: "{{ haproxy_service_configs }}"
26 |
27 | ###########################################################################
28 | # Service frontends and backends assembled from fragments into haproxy.conf
29 | ###########################################################################
30 |
31 | - name: Create haproxy service config files
32 | ansible.builtin.template:
33 | src: service.j2
34 | dest: "/etc/haproxy/conf.d/{{ service.haproxy_service_name }}"
35 | owner: root
36 | group: haproxy
37 | mode: "0640"
38 | # NOTE(damiandabrowski): _haproxy_service_configs_simplified should be replaced
39 | # with haproxy_service_configs in 2024.1.
40 | loop: "{{ _haproxy_service_configs_simplified }}"
41 | loop_control:
42 | loop_var: service
43 | when:
44 | - (service.haproxy_backend_nodes is defined and
45 | service.haproxy_backend_nodes | length > 0) or
46 | (service.haproxy_backup_nodes is defined and
47 | service.haproxy_backup_nodes | length > 0) or
48 | service.haproxy_frontend_only | default('False')
49 | - (service.haproxy_service_enabled | default('True')) | bool
50 | - (service.state is not defined or service.state != 'absent')
51 | notify: Regenerate haproxy configuration
52 |
53 | - name: Remove haproxy service config files for absent services
54 | ansible.builtin.file:
55 | path: "/etc/haproxy/conf.d/{{ service.haproxy_service_name }}"
56 | state: absent
57 | notify: Regenerate haproxy configuration
58 | # NOTE(damiandabrowski): _haproxy_service_configs_simplified should be replaced
59 | # with haproxy_service_configs in 2024.1.
60 | loop: "{{ _haproxy_service_configs_simplified }}"
61 | loop_control:
62 | loop_var: service
63 | when:
64 | - ((service.haproxy_service_enabled | default('True')) | bool) is falsy or (service.state is defined and service.state == 'absent')
65 |
66 | ###########################################################################
67 | # Map files assembled from fragments from each service into .map
68 | ###########################################################################
69 |
70 | - name: Create haproxy map fragment directories
71 | ansible.builtin.file:
72 | state: directory
73 | path: "/etc/haproxy/map.conf.d/{{ item }}"
74 | owner: root
75 | group: haproxy
76 | mode: "0750"
77 | # NOTE(damiandabrowski): _haproxy_service_configs_simplified should be replaced
78 | # with haproxy_service_configs in 2024.1.
79 | loop: >-
80 | {{
81 | _haproxy_service_configs_simplified | selectattr('haproxy_map_entries', 'defined') | map(attribute='haproxy_map_entries') | flatten |
82 | map(attribute='name') | unique
83 | }}
84 |
85 | # create map entries when the service is enabled and an existing map fragment is not absent
86 | - name: Create haproxy map files
87 | vars:
88 | map_file: "/etc/haproxy/map.conf.d/{{ item.1.name }}/{{ item.1.order | default('00') }}-{{ item.0.haproxy_service_name }}.map"
89 | ansible.builtin.template:
90 | src: map.j2
91 | dest: "{{ map_file }}"
92 | owner: root
93 | group: haproxy
94 | mode: "0640"
95 | # NOTE(damiandabrowski): _haproxy_service_configs_simplified should be replaced
96 | # with haproxy_service_configs in 2024.1.
97 | with_subelements:
98 | - "{{ _haproxy_service_configs_simplified | selectattr('haproxy_map_entries', 'defined') }}"
99 | - haproxy_map_entries
100 | when:
101 | - (item.0.haproxy_service_enabled | default(True)) | bool
102 | - item.1.state | default('present') != 'absent'
103 | notify: Regenerate maps
104 | register: map_create
105 |
106 | # remove map entries when the service is not enabled, the service is absent or the map is absent
107 | - name: Delete unused map entries
108 | ansible.builtin.file:
109 | state: absent
110 | path: "/etc/haproxy/map.conf.d/{{ item.1.name }}/{{ item.1.order | default('00') }}-{{ item.0.haproxy_service_name }}.map"
111 | when:
112 | - (item.0.haproxy_service_enabled | default('True')) | bool is falsy or
113 | (item.0.state is defined and item.0.state == 'absent') or
114 | (item.1.state | default('present') == 'absent')
115 | # NOTE(damiandabrowski): _haproxy_service_configs_simplified should be replaced
116 | # with haproxy_service_configs in 2024.1.
117 | with_subelements:
118 | - "{{ _haproxy_service_configs_simplified | selectattr('haproxy_map_entries', 'defined') }}"
119 | - haproxy_map_entries
120 | notify: Regenerate maps
121 | register: map_delete
122 |
--------------------------------------------------------------------------------
/tasks/haproxy_service_config_external.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2023, Cleura AB
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | - name: Gather variables for each operating system
17 | ansible.builtin.include_vars: "{{ lookup('first_found', params) }}"
18 | vars:
19 | params:
20 | files:
21 | - "{{ ansible_facts['distribution'] | lower }}-{{ ansible_facts['distribution_version'] | lower }}.yml"
22 | - "{{ ansible_facts['distribution'] | lower }}-{{ ansible_facts['distribution_major_version'] | lower }}.yml"
23 | - "{{ ansible_facts['os_family'] | lower }}-{{ ansible_facts['distribution_major_version'] | lower }}.yml"
24 | - "{{ ansible_facts['distribution'] | lower }}.yml"
25 | - "{{ ansible_facts['os_family'] | lower }}.yml"
26 | paths:
27 | - "{{ role_path }}/vars"
28 |
29 | - name: Including haproxy_service_config tasks
30 | ansible.builtin.include_tasks: haproxy_service_config.yml
31 | args:
32 | apply:
33 | tags:
34 | - haproxy_server-config
35 | tags:
36 | - always
37 |
--------------------------------------------------------------------------------
/tasks/haproxy_ssl_letsencrypt.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Licensed under the Apache License, Version 2.0 (the "License");
3 | # you may not use this file except in compliance with the License.
4 | # You may obtain a copy of the License at
5 | #
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | #
8 | # Unless required by applicable law or agreed to in writing, software
9 | # distributed under the License is distributed on an "AS IS" BASIS,
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | # See the License for the specific language governing permissions and
12 | # limitations under the License.
13 |
14 | - name: Install certbot from distro package
15 | ansible.builtin.package:
16 | name: "{{ haproxy_distro_certbot_packages }}"
17 | state: present
18 |
19 | - name: Create first time ssl cert with certbot
20 | throttle: 1
21 | ansible.builtin.shell: >
22 | {% if haproxy_ssl_letsencrypt_certbot_challenge == 'http-01' %}
23 | timeout {{ haproxy_ssl_letsencrypt_pre_hook_timeout }}
24 | python3 -m http.server {{ haproxy_ssl_letsencrypt_certbot_backend_port }}
25 | --bind {{ haproxy_ssl_letsencrypt_certbot_bind_address }} || true &&
26 | {% endif %}
27 | {{ haproxy_ssl_letsencrypt_certbot_binary }} certonly
28 | --agree-tos
29 | --non-interactive
30 | --text
31 | --rsa-key-size 4096
32 | --email {{ haproxy_ssl_letsencrypt_email }}
33 | --domains {{ haproxy_ssl_letsencrypt_domains | join(',') }}
34 | {% if haproxy_ssl_letsencrypt_certbot_server is defined %}
35 | --server {{ haproxy_ssl_letsencrypt_certbot_server }}
36 | {% endif %}
37 | {% if haproxy_ssl_letsencrypt_certbot_challenge == 'http-01' %}
38 | --standalone
39 | --http-01-port {{ haproxy_ssl_letsencrypt_certbot_backend_port }}
40 | --http-01-address {{ haproxy_ssl_letsencrypt_certbot_bind_address }}
41 | {% endif %}
42 | {{ haproxy_ssl_letsencrypt_setup_extra_params }}
43 | args:
44 | creates: "{{ haproxy_ssl_letsencrypt_config_path }}/{{ haproxy_ssl_letsencrypt_domains | first }}/fullchain.pem"
45 |
46 | # Certbot automatically installs its systemd timer responsible for renewals
47 | - name: Create certbot pre hook
48 | ansible.builtin.template:
49 | src: letsencrypt_pre_hook_certbot_distro.j2
50 | dest: /etc/letsencrypt/renewal-hooks/pre/haproxy-pre
51 | mode: "0755"
52 | when:
53 | - haproxy_ssl_letsencrypt_certbot_challenge == 'http-01'
54 |
55 | - name: Create certbot post renewal hook
56 | ansible.builtin.template:
57 | src: letsencrypt_renew_certbot_distro.j2
58 | dest: /etc/letsencrypt/renewal-hooks/post/haproxy-renew
59 | mode: "0755"
60 |
61 | - name: Create new pem file for haproxy
62 | ansible.builtin.assemble:
63 | src: "{{ haproxy_ssl_letsencrypt_config_path }}/{{ haproxy_ssl_letsencrypt_domains | first }}"
64 | dest: >-
65 | {{
66 | haproxy_ssl_cert_path ~ '/haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ (item.get('interface')) | ternary(
67 | item.get('address') ~ '-' ~ item.get('interface'), item['address']) ~ '.pem'
68 | }}
69 | regexp: "(privkey|fullchain).pem$"
70 | owner: haproxy
71 | group: haproxy
72 | mode: "0640"
73 | with_items:
74 | - "{{ haproxy_vip_binds | selectattr('type', 'defined') | selectattr('type', 'eq', 'external') }}"
75 | notify:
76 | - Reload haproxy
77 |
--------------------------------------------------------------------------------
/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2014, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | - name: Gather variables for each operating system
17 | ansible.builtin.include_vars: "{{ lookup('first_found', params) }}"
18 | vars:
19 | params:
20 | files:
21 | - "{{ ansible_facts['distribution'] | lower }}-{{ ansible_facts['distribution_version'] | lower }}.yml"
22 | - "{{ ansible_facts['distribution'] | lower }}-{{ ansible_facts['distribution_major_version'] | lower }}.yml"
23 | - "{{ ansible_facts['os_family'] | lower }}-{{ ansible_facts['distribution_major_version'] | lower }}.yml"
24 | - "{{ ansible_facts['distribution'] | lower }}.yml"
25 | - "{{ ansible_facts['os_family'] | lower }}.yml"
26 | paths:
27 | - "{{ role_path }}/vars"
28 | tags:
29 | - always
30 |
31 | - name: Importing haproxy_pre_install tasks
32 | ansible.builtin.import_tasks: haproxy_pre_install.yml
33 | tags:
34 | - haproxy_server-install
35 |
36 | - name: Importing haproxy_install tasks
37 | ansible.builtin.import_tasks: haproxy_install.yml
38 | tags:
39 | - haproxy_server-install
40 |
41 | # NOTE (jrosser) the self signed certificate is also needed for bootstrapping
42 | # letsencrypt, as haproxy will not start with ssl config but a missing certificate
43 | - name: Create and install SSL certificates
44 | ansible.builtin.include_role:
45 | name: pki
46 | apply:
47 | tags:
48 | - haproxy_server-config
49 | - pki
50 | vars:
51 | pki_setup_host: "{{ haproxy_pki_setup_host }}"
52 | pki_dir: "{{ haproxy_pki_dir }}"
53 | pki_create_ca: "{{ haproxy_pki_create_ca }}"
54 | pki_authorities: "{{ haproxy_pki_authorities }}"
55 | pki_install_ca: "{{ haproxy_pki_install_ca }}"
56 | pki_regen_ca: "{{ haproxy_pki_regen_ca }}"
57 | pki_create_certificates: "{{ haproxy_pki_create_certificates }}"
58 | pki_regen_cert: "{{ haproxy_pki_regen_cert }}"
59 | pki_certificates: "{{ haproxy_pki_certificates }}"
60 | pki_install_certificates: "{{ haproxy_pki_install_certificates }}"
61 | pki_handler_cert_installed: "haproxy cert installed"
62 | when:
63 | - haproxy_ssl | bool
64 | tags:
65 | - haproxy_server-config
66 | - pki
67 |
68 | - name: Importing haproxy_post_install tasks
69 | ansible.builtin.import_tasks: haproxy_post_install.yml
70 | tags:
71 | - haproxy_server-config
72 |
73 | # NOTE(jrosser) we must reload the haproxy config before doing the first time certbot setup to ensure the letsencypt backend is configured
74 | - name: Flush handlers
75 | ansible.builtin.meta: flush_handlers
76 |
77 | - name: Including haproxy_ssl_letsencrypt tasks
78 | ansible.builtin.include_tasks: haproxy_ssl_letsencrypt.yml
79 | when:
80 | - haproxy_ssl | bool
81 | - haproxy_ssl_letsencrypt_enable | bool
82 | - haproxy_user_ssl_cert is not defined or haproxy_user_ssl_key is not defined
83 | args:
84 | apply:
85 | tags:
86 | - haproxy_server-config
87 | - letsencrypt
88 | tags:
89 | - haproxy_server-config
90 | - letsencrypt
91 |
--------------------------------------------------------------------------------
/templates/haproxy.cfg.j2:
--------------------------------------------------------------------------------
1 | # {{ ansible_managed }}
2 |
3 | global
4 | log /dev/log local0
5 | chroot /var/lib/haproxy
6 | user haproxy
7 | group haproxy
8 | daemon
9 | maxconn {{ haproxy_maxconn }}
10 | {% for key, value in ((_haproxy_default_tuning_params | default({})) | combine(haproxy_tuning_params)).items() %}
11 | {{ key }} {{ value }}
12 | {% endfor %}
13 | stats socket /var/run/haproxy.stat level admin mode 600
14 | {% if haproxy_ssl | bool %}
15 | ssl-default-bind-options {{ haproxy_ssl_bind_options }}
16 | ssl-default-server-options {{ haproxy_ssl_server_options }}
17 | {% if haproxy_ssl_cipher_suite_tls13 != "" -%}
18 | ssl-default-bind-ciphersuites {{ haproxy_ssl_cipher_suite_tls13 }}
19 | ssl-default-server-ciphersuites {{ haproxy_ssl_cipher_suite_tls13 }}
20 | {% endif -%}
21 | {% if haproxy_ssl_cipher_suite_tls12 != "" -%}
22 | ssl-default-bind-ciphers {{ haproxy_ssl_cipher_suite_tls12 }}
23 | ssl-default-server-ciphers {{ haproxy_ssl_cipher_suite_tls12 }}
24 | {% endif -%}
25 | tune.ssl.default-dh-param {{ haproxy_ssl_dh_param }}
26 | {% endif %}
27 |
28 | defaults
29 | log global
30 | option dontlognull
31 | option redispatch
32 | option {{ haproxy_keepalive_mode }}
33 | retries {{ haproxy_retries }}
34 | timeout client {{ haproxy_client_timeout }}
35 | timeout connect {{ haproxy_connect_timeout }}
36 | timeout http-request {{ haproxy_http_request_timeout }}
37 | timeout server {{ haproxy_server_timeout }}
38 | maxconn {{ haproxy_maxconn }}
39 | {% for value in haproxy_errorfiles %}
40 | errorfile {{ value.code }} {{ value.path }}
41 | {% endfor %}
42 | {% if haproxy_stats_enabled | bool %}
43 | {% set haproxy_ssl_path = haproxy_ssl_cert_path + "/haproxy_" + (haproxy_host | default(ansible_facts['hostname'])) + "-" + ((haproxy_bind_internal_lb_vip_interface is truthy) | ternary(haproxy_bind_internal_lb_vip_address ~ '-' ~ haproxy_bind_internal_lb_vip_interface, haproxy_bind_internal_lb_vip_address)) + ".pem" %}
44 | listen stats
45 | bind {{ haproxy_stats_bind_address }}:{{ haproxy_stats_port }} {% if haproxy_stats_ssl | bool %}ssl crt {{ haproxy_stats_ssl_cert_path | default(haproxy_ssl_path) }} {% if haproxy_stats_ssl_client_cert_ca is defined %}verify required ca-file {{ haproxy_stats_ssl_client_cert_ca }}{% endif %}{% endif %}
46 |
47 | mode http
48 | {% if haproxy_stats_prometheus_enabled | bool %}
49 | http-request use-service prometheus-exporter if { path /metrics }
50 | {% endif %}
51 | stats enable
52 | stats hide-version
53 | stats realm Haproxy\ Statistics
54 | stats uri /
55 | stats show-node
56 | stats show-legends
57 | stats auth {{ haproxy_username }}:{{ haproxy_stats_password }}
58 | stats admin if TRUE
59 | stats refresh {{ haproxy_stats_refresh_interval }}s
60 | {% endif %}
61 |
--------------------------------------------------------------------------------
/templates/letsencrypt_pre_hook_certbot_distro.j2:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # swing load balancer over to this node by starting temporary http server for {{ haproxy_ssl_letsencrypt_pre_hook_timeout }} seconds
3 |
4 | timeout {{ haproxy_ssl_letsencrypt_pre_hook_timeout }} python3 -m http.server {{ haproxy_ssl_letsencrypt_certbot_backend_port }} --bind {{ haproxy_ssl_letsencrypt_certbot_bind_address }}
5 |
--------------------------------------------------------------------------------
/templates/letsencrypt_renew_certbot_distro.j2:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # renew cert if required and copy to haproxy destination
3 |
4 | {% for vip in haproxy_vip_binds | selectattr('type', 'defined') | selectattr('type', 'eq', 'external') %}
5 | cat /etc/letsencrypt/live/{{ haproxy_ssl_letsencrypt_domains | first }}/{fullchain,privkey}.pem \
6 | > {{ haproxy_ssl_cert_path ~ '/haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ (vip.get('interface')) | ternary(vip['address'] ~ '-' ~ vip.get('interface'), vip['address']) ~ '.pem' }}
7 | {% endfor %}
8 |
9 | systemctl reload haproxy
10 |
--------------------------------------------------------------------------------
/templates/map.j2:
--------------------------------------------------------------------------------
1 | {% for m in item.1.entries %}
2 | {{ m }}
3 | {% endfor %}
4 |
--------------------------------------------------------------------------------
/templates/service-redirect.j2:
--------------------------------------------------------------------------------
1 | {% set haproxy_http_front_port = (haproxy_backend_port | int) + 10000 %}
2 | {% set haproxy_https_front_port = (haproxy_backend_port | int) + 20000 %}
3 |
4 | # Redirect request to HTTP or HTTPS frontend based on used protocol
5 | frontend {{ service.haproxy_service_name }}-tcp-redirect-front-{{ loop.index }}
6 | mode tcp
7 | bind {{ vip_address }}:{{ service.haproxy_port }}{{ (vip_interface is truthy) | ternary(' interface ' ~ vip_interface, '') }}
8 | tcp-request inspect-delay 2s
9 | tcp-request content accept if HTTP
10 | tcp-request content accept if { req.ssl_hello_type 1 }
11 | use_backend {{ value.backend_name | default(service.haproxy_service_name) }}-redirect-http-back-{{ loop.index }} if HTTP
12 | default_backend {{ value.backend_name | default(service.haproxy_service_name) }}-redirect-https-back-{{ loop.index }}
13 |
14 | backend {{ value.backend_name | default(service.haproxy_service_name) }}-redirect-http-back-{{ loop.index }}
15 | mode tcp
16 | server {{ value.backend_name | default(service.haproxy_service_name) }}-http {{ vip_address }}:{{ haproxy_http_front_port }}
17 |
18 | backend {{ value.backend_name | default(service.haproxy_service_name) }}-redirect-https-back-{{ loop.index }}
19 | mode tcp
20 | server {{ value.backend_name | default(service.haproxy_service_name) }}-https {{ vip_address }}:{{ haproxy_https_front_port }}
21 |
22 | frontend {{ service.haproxy_service_name }}-http-front-{{ loop.index }}
23 | bind {{ vip_address }}:{{ haproxy_http_front_port }}{{ (vip_interface is truthy) | ternary(' interface ' ~ vip_interface, '') }}
24 | {% if request_option == "http" %}
25 | option httplog
26 | option forwardfor except 127.0.0.0/8
27 | {% if service.haproxy_http_keepalive_mode is defined %}
28 | option {{ service.haproxy_http_keepalive_mode }}
29 | {% endif %}
30 | {% elif request_option == "tcp" %}
31 | option tcplog
32 | {% endif %}
33 | {% if service.haproxy_timeout_client is defined %}
34 | timeout client {{ service.haproxy_timeout_client }}
35 | {% endif %}
36 | {% if service.haproxy_allowlist_networks is defined %}
37 | acl allow_list src 127.0.0.1/8 {{ service.haproxy_allowlist_networks | join(' ') }}
38 | tcp-request content accept if allow_list
39 | tcp-request content reject
40 | {% endif %}
41 | {% if service.haproxy_acls is defined %}
42 | {% for key, value in service.haproxy_acls.items() %}
43 | acl {{ key }} {{ value.rule }}
44 | {% if not service.haproxy_frontend_only | default(false) %}
45 | use_backend {{ value.backend_name | default(service.haproxy_service_name) }}-back if {{ key }}
46 | {% endif %}
47 | {% endfor %}
48 | {% endif %}
49 | {% for entry in service.haproxy_maps | default([]) %}
50 | {{ entry }}
51 | {% endfor %}
52 | mode {{ service.haproxy_balance_type }}
53 | {% if (not service.haproxy_frontend_only | default(false)) or ((service.haproxy_default_backend is defined) and (service.haproxy_default_backend | length > 0)) %}
54 | default_backend {{ service.haproxy_default_backend | default(service.haproxy_service_name) }}-back
55 | {% endif %}
56 | {% for entry in (service.haproxy_frontend_raw|default([])) + haproxy_frontend_extra_raw %}
57 | {{ entry }}
58 | {% endfor %}
59 |
60 | frontend {{ service.haproxy_service_name }}-https-front-{{ loop.index }}
61 | bind {{ vip_address }}:{{ haproxy_https_front_port }}{{ (vip_interface is truthy) | ternary(' interface ' ~ vip_interface, '') }} ssl crt {{ haproxy_ssl_cert_path }}/haproxy_{{ ansible_facts['hostname'] }}-{{ vip_address }}.pem
62 | {% if request_option == "http" %}
63 | option httplog
64 | option forwardfor except 127.0.0.0/8
65 | {% if service.haproxy_http_keepalive_mode is defined %}
66 | option {{ service.haproxy_http_keepalive_mode }}
67 | {% endif %}
68 | {% elif request_option == "tcp" %}
69 | option tcplog
70 | {% endif %}
71 | {% if service.haproxy_timeout_client is defined %}
72 | timeout client {{ service.haproxy_timeout_client }}
73 | {% endif %}
74 | {% if service.haproxy_allowlist_networks is defined %}
75 | acl allow_list src 127.0.0.1/8 {{ service.haproxy_allowlist_networks | join(' ') }}
76 | tcp-request content accept if allow_list
77 | tcp-request content reject
78 | {% endif %}
79 | {% if service.haproxy_acls is defined %}
80 | {% for key, value in service.haproxy_acls.items() %}
81 | acl {{ key }} {{ value.rule }}
82 | {% if not service.haproxy_frontend_only | default(false) %}
83 | use_backend {{ value.backend_name | default(service.haproxy_service_name) }}-back if {{ key }}
84 | {% endif %}
85 | {% endfor %}
86 | {% endif %}
87 | {% for entry in service.haproxy_maps | default([]) %}
88 | {{ entry }}
89 | {% endfor %}
90 | {% if (service.haproxy_ssl | default(false) | bool) and request_option == 'http' and (loop.index == 1 or vip_address in extra_lb_tls_vip_addresses or (service.haproxy_ssl_all_vips | default(false) | bool and vip_address not in extra_lb_vip_addresses)) %}
91 | http-request add-header X-Forwarded-Proto https
92 | {% endif %}
93 | mode {{ service.haproxy_balance_type }}
94 | {% if (not service.haproxy_frontend_only | default(false)) or ((service.haproxy_default_backend is defined) and (service.haproxy_default_backend | length > 0)) %}
95 | default_backend {{ service.haproxy_default_backend | default(service.haproxy_service_name) }}-back
96 | {% endif %}
97 | {% for entry in (service.haproxy_frontend_raw|default([])) + haproxy_frontend_extra_raw %}
98 | {{ entry }}
99 | {% endfor %}
100 |
--------------------------------------------------------------------------------
/templates/service.j2:
--------------------------------------------------------------------------------
1 | # {{ ansible_managed }}
2 |
3 | {% set request_option = service.haproxy_balance_type | default("http") -%}
4 | {% if service.haproxy_backend_port is not defined %}
5 | {% set haproxy_backend_port = service.haproxy_port %}
6 | {% else %}
7 | {% set haproxy_backend_port = service.haproxy_backend_port %}
8 | {% endif -%}
9 | {% if service.haproxy_check_port is not defined %}
10 | {% set haproxy_check_port = haproxy_backend_port %}
11 | {% else %}
12 | {% set haproxy_check_port = service.haproxy_check_port %}
13 | {% endif -%}
14 |
15 | {% if service.haproxy_bind is defined %}
16 | {% set vip_binds = service.haproxy_bind %}
17 | {% else %}
18 | {% set vip_binds = haproxy_vip_binds + extra_lb_vip_addresses %}
19 | {% endif %}
20 |
21 | {% if not service.haproxy_backend_only | default(false) %}
22 | {% for vip_bind in vip_binds %}
23 | {% if vip_bind is not string and vip_bind is mapping %}
24 | {% set vip_address = vip_bind['address'] %}
25 | {% set vip_interface = vip_bind['interface'] | default('') %}
26 | {% else %}
27 | {% set vip_address = vip_bind %}
28 | {% set vip_interface = '' %}
29 | {% endif %}
30 | {% if service.haproxy_redirect_http_port is defined and service.haproxy_ssl %}
31 | {% if (loop.index == 1 or service.haproxy_ssl_all_vips | default(false) | bool) %}
32 |
33 | frontend {{ service.haproxy_service_name }}-redirect-front-{{ loop.index }}
34 | bind {{ vip_address }}:{{ service.haproxy_redirect_http_port }}{{ (vip_interface is truthy) | ternary(' interface ' ~ vip_interface, '') }}
35 | mode http
36 | redirect scheme {{ service.haproxy_redirect_scheme | default('https if !{ ssl_fc }') }}
37 | {% if service.haproxy_frontend_acls is defined %}
38 | {% for key, value in service.haproxy_frontend_acls.items() %}
39 | acl {{ key }} {{ value.rule }}
40 | use_backend {{ value.backend_name | default(service.haproxy_service_name) }}-back if {{ key }}
41 | {% endfor %}
42 | {% for entry in haproxy_frontend_redirect_extra_raw %}
43 | {{ entry }}
44 | {% endfor %}
45 | {% endif %}
46 | {% endif %}
47 | {% endif %}
48 |
49 | {# service-redirect.j2 allows frontend to handle both HTTP and HTTPS connections. #}
50 | {# This is especially useful during HTTP->HTTPS service endpoint transition. #}
51 | {% if service.haproxy_accept_both_protocols | default(false) %}
52 | {% include 'service-redirect.j2' %}
53 | {% else %}
54 | {% set haproxy_ssl_path=haproxy_ssl_cert_path + "/haproxy_" + (haproxy_host | default(ansible_facts['hostname'])) + "-" + ((vip_interface is truthy) | ternary(vip_address ~ '-' ~ vip_interface, vip_address)) + ".pem" %}
55 | frontend {{ service.haproxy_service_name }}-front-{{ loop.index }}
56 | bind {{ vip_address }}:{{ service.haproxy_port }}{{ (vip_interface is truthy) | ternary(' interface ' ~ vip_interface, '') }} {% if (service.haproxy_ssl | default(false) | bool) and (request_option == "http") and (loop.index == 1 or vip_address in extra_lb_tls_vip_addresses or (service.haproxy_ssl_all_vips | default(false) | bool and vip_address not in extra_lb_vip_addresses)) %}ssl crt {{ service.haproxy_ssl_path | default(haproxy_ssl_path) }}{% if service.haproxy_frontend_h2 | default(haproxy_frontend_h2) %} alpn h2,http/1.1{% endif %}{% endif %}
57 |
58 | {% if request_option == "http" %}
59 | option httplog
60 | option forwardfor except 127.0.0.0/8
61 | {% if service.haproxy_http_keepalive_mode is defined %}
62 | option {{ service.haproxy_http_keepalive_mode }}
63 | {% endif %}
64 | {% elif request_option == "tcp" %}
65 | option tcplog
66 | {% endif %}
67 | {% if service.haproxy_timeout_client is defined %}
68 | timeout client {{ service.haproxy_timeout_client }}
69 | {% endif %}
70 | {% if service.haproxy_allowlist_networks is defined %}
71 | acl allow_list src 127.0.0.1/8 {{ service.haproxy_allowlist_networks | join(' ') }}
72 | tcp-request content accept if allow_list
73 | tcp-request content reject
74 | {% endif %}
75 | {% if service.haproxy_acls is defined %}
76 | {% for key, value in service.haproxy_acls.items() %}
77 | acl {{ key }} {{ value.rule }}
78 | {% if not service.haproxy_frontend_only | default(false) %}
79 | use_backend {{ value.backend_name | default(service.haproxy_service_name) }}-back if {{ key }}
80 | {% endif %}
81 | {% endfor %}
82 | {% endif %}
83 | {% for entry in service.haproxy_maps | default([]) %}
84 | {{ entry }}
85 | {% endfor %}
86 | {% if (service.haproxy_ssl | default(false) | bool) and request_option == 'http' and (loop.index == 1 or vip_address in extra_lb_tls_vip_addresses or (service.haproxy_ssl_all_vips | default(false) | bool and vip_address not in extra_lb_vip_addresses)) %}
87 | http-request add-header X-Forwarded-Proto https
88 | {% endif %}
89 | mode {{ request_option }}
90 | {% if (not service.haproxy_frontend_only | default(false)) or ((service.haproxy_default_backend is defined) and (service.haproxy_default_backend | length > 0)) %}
91 | default_backend {{ service.haproxy_default_backend | default(service.haproxy_service_name) }}-back
92 | {% endif %}
93 | {% for entry in (service.haproxy_frontend_raw|default([])) + haproxy_frontend_extra_raw %}
94 | {{ entry }}
95 | {% endfor %}
96 | {% endif %}
97 | {% endfor %}
98 | {% endif %}
99 |
100 | {% if not service.haproxy_frontend_only | default(false) %}
101 | {% set backend_options = service.haproxy_backend_options|default([]) %}
102 | {% set backend_arguments = service.haproxy_backend_arguments|default([]) %}
103 |
104 | backend {{ service.haproxy_service_name }}-back
105 | mode {{ request_option }}
106 | balance {{ service.haproxy_balance_alg|default("leastconn") }}
107 | {% if service.haproxy_timeout_server is defined %}
108 | timeout server {{ service.haproxy_timeout_server }}
109 | {% endif %}
110 | {% if (service.haproxy_stick_table_enabled | default(true) | bool) %}
111 | {% set stick_table = service.haproxy_stick_table|default( haproxy_stick_table | default([])) %}
112 | {% for entry in stick_table %}
113 | {{ entry }}
114 | {% endfor %}
115 | {% endif %}
116 | {% if request_option == "http" %}
117 | option forwardfor
118 | {% endif %}
119 | {% for option in backend_options %}
120 | option {{ option }}
121 | {% endfor %}
122 | {% for argument in backend_arguments %}
123 | {{ argument }}
124 | {% endfor %}
125 | {% set backend_httpcheck_options = service.haproxy_backend_httpcheck_options|default([]) %}
126 | {% if backend_httpcheck_options %}
127 | option httpchk
128 | {% for option in backend_httpcheck_options %}
129 | http-check {{ option }}
130 | {% endfor %}
131 | {% endif %}
132 |
133 |
134 | {% for host_name in service.haproxy_backend_nodes %}
135 | {% set __ip_addr = host_name.ip_addr | default(hostvars[host_name]['ansible_host']) %}
136 | {% set __host_name = host_name.name | default(host_name) | string %}
137 | {% set __backend_port = host_name.backend_port | default(haproxy_backend_port) | string %}
138 | {% set __check_port = host_name.check_port | default(haproxy_check_port) | string %}
139 | {% set entry = [] %}
140 | {% set _ = entry.append("server") %}
141 | {% set _ = entry.append(__host_name) %}
142 | {% set _ = entry.append(__ip_addr + ":" + __backend_port) %}
143 | {% set _ = entry.append("check") %}
144 | {% set _ = entry.append("port") %}
145 | {% set _ = entry.append(__check_port) %}
146 | {% set _ = entry.append("inter") %}
147 | {% set _ = entry.append(service.interval | default(haproxy_interval) | string) %}
148 | {% set _ = entry.append("rise") %}
149 | {% set _ = entry.append(service.backend_rise | default(haproxy_rise) | string) %}
150 | {% set _ = entry.append("fall") %}
151 | {% set _ = entry.append(service.backend_fall | default(haproxy_fall) | string) %}
152 | {% if service.haproxy_backend_ssl | default(False) %}
153 | {% set _ = entry.append("ssl") %}
154 | {% if service.haproxy_backend_ssl_check | default(service.haproxy_backend_ssl) %}
155 | {% set _ = entry.append("check-ssl") %}
156 | {% endif %}
157 | {% if service.haproxy_backend_ca | default(False) %}
158 | {% set _ = entry.append("ca-file") %}
159 | {% set _ = entry.append(service.haproxy_backend_ca is string | ternary(service.haproxy_backend_ca, haproxy_system_ca)) %}
160 | {% else %}
161 | {% set _ = entry.append("verify none") %}
162 | {% endif %}
163 | {% if service.haproxy_backend_h2 | default(haproxy_backend_h2) and request_option == "http" %}
164 | {% set _ = entry.append("alpn h2,http/1.1") %}
165 | {% endif %}
166 | {% else %}
167 | {% if service.haproxy_backend_h2 | default(haproxy_backend_h2) and request_option == "http" %}
168 | {% set _ = entry.append("proto h2") %}
169 | {% endif %}
170 | {% endif %}
171 | {% set backend_server_options = service.haproxy_backend_server_options|default([]) %}
172 | {% for option in backend_server_options %}
173 | {% set _ = entry.append(option) %}
174 | {% endfor %}
175 | {% set backend_per_server_options = host_name.backend_server_options|default([]) %}
176 | {% for option in backend_per_server_options %}
177 | {% set _ = entry.append(option) %}
178 | {% endfor %}
179 | {{ entry | join(' ') }}
180 | {% endfor %}
181 |
182 | {% for host_name in service.haproxy_backup_nodes | default([]) %}
183 | {% set __ip_addr = host_name.ip_addr | default(hostvars[host_name]['ansible_host']) %}
184 | {% set __host_name = host_name.name | default(host_name) | string %}
185 | {% set __backend_port = host_name.backend_port | default(haproxy_backend_port) | string %}
186 | {% set __check_port = host_name.check_port | default(haproxy_check_port) | string %}
187 | {% set entry = [] %}
188 | {% set _ = entry.append("server") %}
189 | {% set _ = entry.append(__host_name) %}
190 | {% set _ = entry.append(__ip_addr + ":" + __backend_port) %}
191 | {% set _ = entry.append("check") %}
192 | {% set _ = entry.append("port") %}
193 | {% set _ = entry.append(__check_port) %}
194 | {% set _ = entry.append("inter") %}
195 | {% set _ = entry.append(service.interval | default(haproxy_interval) | string) %}
196 | {% set _ = entry.append("rise") %}
197 | {% set _ = entry.append(service.backup_rise | default(haproxy_rise) | string) %}
198 | {% set _ = entry.append("fall") %}
199 | {% set _ = entry.append(service.backup_fall | default(haproxy_fall) | string) %}
200 | {% set _ = entry.append("backup") %}
201 | {% if service.haproxy_backend_ssl | default(False) %}
202 | {% set _ = entry.append("ssl") %}
203 | {% if service.haproxy_backend_ssl_check | default(service.haproxy_backend_ssl) %}
204 | {% set _ = entry.append("check-ssl") %}
205 | {% endif %}
206 | {% if service.haproxy_backend_ca | default(False) %}
207 | {% set _ = entry.append("ca-file") %}
208 | {% set _ = entry.append(service.haproxy_backend_ca is string | ternary(service.haproxy_backend_ca, haproxy_system_ca)) %}
209 | {% else %}
210 | {% set _ = entry.append("verify none") %}
211 | {% endif %}
212 | {% endif %}
213 | {% set backend_server_options = service.haproxy_backend_server_options|default([]) %}
214 | {% for option in backend_server_options %}
215 | {% set _ = entry.append(option) %}
216 | {% endfor %}
217 | {% set backend_per_server_options = host_name.backend_server_options|default([]) %}
218 | {% for option in backend_per_server_options %}
219 | {% set _ = entry.append(option) %}
220 | {% endfor %}
221 | {{ entry | join(' ') }}
222 | {% endfor %}
223 | {% endif %}
224 |
--------------------------------------------------------------------------------
/tests/ansible-role-requirements.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: apt_package_pinning
3 | src: https://opendev.org/openstack/openstack-ansible-apt_package_pinning
4 | scm: git
5 | version: master
6 |
--------------------------------------------------------------------------------
/tests/host_vars/localhost.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2017, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | ansible_host: 127.0.0.1
16 |
--------------------------------------------------------------------------------
/tests/inventory:
--------------------------------------------------------------------------------
1 | [all]
2 | localhost
3 |
4 | [haproxy_all]
5 | localhost
6 |
--------------------------------------------------------------------------------
/tests/test-vars.yml:
--------------------------------------------------------------------------------
1 | ---
2 | external_lb_vip_address: 127.0.0.1
3 | internal_lb_vip_address: 127.0.0.1
4 | haproxy_service_configs:
5 | - service:
6 | haproxy_service_name: test_group
7 | haproxy_backend_nodes: "{{ groups['haproxy_all'] | default([]) }}"
8 | haproxy_port: 8180
9 | haproxy_backend_port: 22
10 | haproxy_ssl: False
11 | haproxy_balance_type: tcp
12 | haproxy_backend_options:
13 | - tcp-check
14 | - service:
15 | haproxy_service_name: test_list
16 | haproxy_backend_nodes:
17 | - name: "localhost"
18 | ip_addr: "127.0.0.1"
19 | haproxy_port: 8181
20 | haproxy_backend_port: 22
21 | haproxy_ssl: False
22 | haproxy_balance_type: tcp
23 | haproxy_backend_options:
24 | - tcp-check
25 | - service:
26 | haproxy_service_name: test_backend_ssl
27 | haproxy_backend_nodes: "{{ groups['haproxy_all'] | default([]) }}"
28 | haproxy_port: 8180
29 | haproxy_backend_port: 443
30 | haproxy_backend_ssl: True
31 | haproxy_backend_ca: False
32 | haproxy_ssl: False
33 | haproxy_balance_type: http
34 | - service:
35 | haproxy_service_name: test_absent_service
36 | haproxy_backend_nodes:
37 | - name: "localhost"
38 | ip_addr: "127.0.0.1"
39 | haproxy_port: 65535
40 | haproxy_balance_type: tcp
41 | state: "{{ absent_service_state }}"
42 |
--------------------------------------------------------------------------------
/tests/test.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2016, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | - name: Playbook for role testing
17 | hosts: localhost
18 | connection: local
19 | user: root
20 | become: true
21 | vars_files:
22 | - test-vars.yml
23 | tasks:
24 | - name: Create marker file for idempotence
25 | copy:
26 | content: mark
27 | dest: /tmp/haproxy_pass1
28 | register: haproxy_pass1
29 |
30 | - name: Set fact for idempotence test
31 | set_fact:
32 | idempotence_pass_1: "{{ haproxy_pass1 is changed }}"
33 |
34 | - name: Set fact for absent service state
35 | set_fact:
36 | absent_service_state: "{{ (haproxy_pass1 is changed) | ternary('present', 'absent') }}"
37 |
38 | - name: Run the haproxy_server role
39 | include_role:
40 | name: "haproxy_server"
41 |
42 | - name: Run role again on first pass
43 | when:
44 | - "idempotence_pass_1 | bool"
45 | block:
46 | - name: Ensure the absent service is present
47 | stat:
48 | path: "/etc/haproxy/conf.d/test_absent_service"
49 | register: absent_services
50 | failed_when: not absent_services.stat.exists
51 |
52 | - name: Set fact for absent service state
53 | set_fact:
54 | absent_service_state: "absent"
55 |
56 | - name: Run the haproxy_server role (again)
57 | include_role:
58 | name: "haproxy_server"
59 |
60 | - name: Ensure the absent service is missing
61 | stat:
62 | path: "/etc/haproxy/conf.d/test_absent_service"
63 | register: absent_services
64 | when:
65 | - "not (idempotence_pass_1 | bool)"
66 | failed_when: absent_services.stat.exists
67 |
68 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | minversion = 3.1
3 | skipsdist = True
4 | envlist = docs,linters,functional
5 | ignore_basepython_conflict = True
6 |
7 | [testenv]
8 | basepython = python3
9 | usedevelop = False
10 | install_command =
11 | pip install -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} {opts} {packages}
12 | commands =
13 | /usr/bin/find . -type f -name "*.pyc" -delete
14 | passenv =
15 | COMMON_TESTS_PATH
16 | HOME
17 | http_proxy
18 | HTTP_PROXY
19 | https_proxy
20 | HTTPS_PROXY
21 | no_proxy
22 | NO_PROXY
23 | TESTING_BRANCH
24 | TESTING_HOME
25 | USER
26 | allowlist_externals =
27 | bash
28 | setenv =
29 | PYTHONUNBUFFERED=1
30 | ROLE_NAME=haproxy_server
31 | TEST_IDEMPOTENCE=true
32 | VIRTUAL_ENV={envdir}
33 | WORKING_DIR={toxinidir}
34 |
35 | [testenv:docs]
36 | deps = -r{toxinidir}/doc/requirements.txt
37 | commands =
38 | bash -c "rm -rf doc/build"
39 | doc8 doc
40 | sphinx-build -W --keep-going -b html doc/source doc/build/html
41 |
42 | [testenv:pdf-docs]
43 | deps = {[testenv:docs]deps}
44 | allowlist_externals =
45 | make
46 | commands =
47 | sphinx-build -W --keep-going -b latex doc/source doc/build/pdf
48 | make -C doc/build/pdf
49 |
50 | [doc8]
51 | # Settings for doc8:
52 | extensions = .rst
53 |
54 | [testenv:releasenotes]
55 | deps = -r{toxinidir}/doc/requirements.txt
56 | commands =
57 | sphinx-build -a -E -W -d releasenotes/build/doctrees --keep-going -b html releasenotes/source releasenotes/build/html
58 |
59 | # environment used by the -infra templated docs job
60 | [testenv:venv]
61 | commands =
62 | {posargs}
63 |
64 | [testenv:pep8]
65 | commands =
66 | bash -c "{toxinidir}/tests/common/test-pep8.sh"
67 |
68 | [flake8]
69 | # Ignores the following rules due to how ansible modules work in general
70 | # F403 'from ansible.module_utils.basic import *' used;
71 | # unable to detect undefined names
72 | ignore=F403
73 |
74 | [testenv:bashate]
75 | commands =
76 | bash -c "{toxinidir}/tests/common/test-bashate.sh"
77 |
78 | [testenv:ansible-syntax]
79 | commands =
80 | bash -c "{toxinidir}/tests/common/test-ansible-syntax.sh"
81 |
82 | [testenv:ansible-lint]
83 | commands =
84 | bash -c "{toxinidir}/tests/common/test-ansible-lint.sh"
85 |
86 | [testenv:functional]
87 | commands =
88 | bash -c "{toxinidir}/tests/common/test-ansible-functional.sh"
89 |
90 | [testenv:linters]
91 | commands =
92 | bash -c "{toxinidir}/tests/common/test-ansible-env-prep.sh"
93 | {[testenv:pep8]commands}
94 | {[testenv:bashate]commands}
95 | {[testenv:ansible-lint]commands}
96 | {[testenv:ansible-syntax]commands}
97 |
--------------------------------------------------------------------------------
/vars/debian.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2016, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | ## APT Cache options
17 | cache_timeout: 600
18 |
19 | haproxy_distro_packages:
20 | - haproxy
21 | - "{{ (ansible_facts['distribution_release'] == 'bookworm' or
22 | ansible_facts['distribution_release'] == 'noble')
23 | | ternary('netcat-openbsd', 'netcat') }}" # Used for the Ansible haproxy module
24 | - psmisc
25 | - vim-haproxy
26 |
27 | haproxy_distro_certbot_packages:
28 | - certbot
29 |
30 | # Set system CA store which can be used to verify backends
31 | haproxy_system_ca: /etc/ssl/certs/ca-certificates.crt
32 |
--------------------------------------------------------------------------------
/vars/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2021, City Network International AB
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | _haproxy_vip_binds: |
17 | {% set vip_binds = [{'address': haproxy_bind_external_lb_vip_address, 'interface': haproxy_bind_external_lb_vip_interface, 'type': 'external'}] %}
18 | {% if haproxy_bind_internal_lb_vip_address != haproxy_bind_external_lb_vip_address or
19 | haproxy_bind_external_lb_vip_interface != haproxy_bind_internal_lb_vip_interface %}
20 | {% set _ = vip_binds.append({'address': haproxy_bind_internal_lb_vip_address, 'interface': haproxy_bind_internal_lb_vip_interface, 'type': 'internal'}) %}
21 | {% endif %}
22 | {% for vip_address in extra_lb_tls_vip_addresses %}
23 | {% set _ = vip_binds.append({'address': vip_address, 'type': 'external'}) %}
24 | {% endfor %}
25 | {{ vip_binds }}
26 |
27 | _haproxy_pki_certificates: |
28 | {% set _pki_certs = [] %}
29 | {% for vip in haproxy_vip_binds %}
30 | {% set _vip_interface = vip['interface'] | default('') %}
31 | {% set san = ['DNS:' ~ ansible_facts['hostname'], 'DNS:' ~ ansible_facts['fqdn']] %}
32 | {% if vip['address'] != '*' %}
33 | {% set _ = san.append((vip['address'] | ansible.utils.ipaddr) | ternary('IP:', 'DNS:') ~ vip['address']) %}
34 | {% endif %}
35 | {% if vip['address'] == haproxy_bind_internal_lb_vip_address and not (internal_lb_vip_address | ansible.utils.ipaddr) %}
36 | {% set _ = san.append('DNS:' ~ internal_lb_vip_address) %}
37 | {% endif %}
38 | {% if vip['address'] == haproxy_bind_external_lb_vip_address and not (external_lb_vip_address | ansible.utils.ipaddr) %}
39 | {% set _ = san.append('DNS:' ~ external_lb_vip_address) %}
40 | {% endif %}
41 | {% for record in vip.get('pki_san_records', []) %}
42 | {% set _ = san.append((record | ansible.utils.ipaddr) | ternary('IP:', 'DNS:') ~ record) %}
43 | {% endfor %}
44 | {% set _ = _pki_certs.append(
45 | {
46 | 'name': 'haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ (_vip_interface is truthy) | ternary(vip['address'] ~ '-' ~ _vip_interface, vip['address']),
47 | 'provider': 'ownca',
48 | 'cn': ansible_facts['hostname'],
49 | 'san': san | join(','),
50 | 'signed_by': haproxy_pki_intermediate_cert_name,
51 | }
52 | ) %}
53 | {% endfor %}
54 | {{ _pki_certs }}
55 |
56 | _haproxy_pki_install_certificates: |
57 | {% set _pki_install = [] %}
58 | {% for vip in haproxy_vip_binds %}
59 | {% set _vip_interface = vip['interface'] | default('') %}
60 | {% set _cert_basename = '/haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ (_vip_interface is truthy) | ternary(
61 | vip['address'] ~ '-' ~ _vip_interface, vip['address'])
62 | %}
63 | {% set _ = _pki_install.append(
64 | {
65 | 'src': haproxy_user_ssl_cert | default(haproxy_pki_certs_path ~ _cert_basename ~ '.crt'),
66 | 'dest': haproxy_ssl_temp_path ~ _cert_basename ~ '.crt',
67 | 'owner': 'root',
68 | 'group': 'root',
69 | 'mode': '0644'
70 | }
71 | )
72 | %}
73 | {% set _ = _pki_install.append(
74 | {
75 | 'src': haproxy_user_ssl_key | default(haproxy_pki_keys_path ~ _cert_basename ~ '.key.pem'),
76 | 'dest': haproxy_ssl_temp_path ~ _cert_basename ~ '.key',
77 | 'owner': 'root',
78 | 'group': 'root',
79 | 'mode': '0644'
80 | }
81 | )
82 | %}
83 | {# We need to put CA only when it's provided by user or internal CA is used and user certs are not provided #}
84 | {% if (haproxy_user_ssl_cert is not defined and haproxy_user_ssl_key is not defined) or haproxy_user_ssl_ca_cert is defined %}
85 | {% set _ = _pki_install.append(
86 | {
87 | 'src': haproxy_user_ssl_ca_cert | default(haproxy_pki_intermediate_cert_path),
88 | 'dest': haproxy_ssl_temp_path ~ _cert_basename ~ '-ca.crt',
89 | 'owner': 'root',
90 | 'group': 'root',
91 | 'mode': '0644'
92 | })
93 | %}
94 | {% endif %}
95 | {% endfor %}
96 | {{ _pki_install }}
97 |
98 | # In case CSP is enabled, on newer haproxy versions, header size
99 | # fill more than bufsize-maxrewrite, which results in 500
100 | # See: https://github.com/haproxy/haproxy/issues/1597
101 | _haproxy_default_tuning_params:
102 | tune.maxrewrite: 1280
103 |
--------------------------------------------------------------------------------
/vars/redhat.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2016, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | haproxy_distro_packages:
17 | - haproxy
18 | - nc # Used for the Ansible haproxy module
19 |
20 | # Set system CA store which can be used to verify backends
21 | haproxy_system_ca: /etc/pki/tls/certs/ca-bundle.crt
22 |
--------------------------------------------------------------------------------
/zuul.d/project.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # Copyright 2017, Rackspace US, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | - project:
17 | templates:
18 | - openstack-ansible-linters-jobs
19 | - openstack-ansible-deploy-infra_lxc-jobs
20 | - openstack-ansible-deploy-aio_metal-jobs
21 | - openstack-ansible-upgrade-infra_lxc-jobs
22 | - check-requirements
23 | - publish-openstack-docs-pti
24 | - build-release-notes-jobs-python3
25 |
--------------------------------------------------------------------------------