114 lines
4.1 KiB
Python
114 lines
4.1 KiB
Python
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from neutron_lib import constants
|
|
from oslo_log import log as logging
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
PROXY_SERVICE_NAME = 'haproxy'
|
|
PROXY_SERVICE_CMD = 'haproxy'
|
|
|
|
|
|
class InvalidUserOrGroupException(Exception):
|
|
pass
|
|
|
|
|
|
METADATA_HAPROXY_GLOBAL = """
|
|
global
|
|
log /dev/log local0 %(log_level)s
|
|
log-tag %(log_tag)s
|
|
user %(user)s
|
|
group %(group)s
|
|
maxconn 1024
|
|
pidfile %(pidfile)s
|
|
daemon
|
|
|
|
defaults
|
|
log global
|
|
mode http
|
|
option httplog
|
|
option dontlognull
|
|
option http-server-close
|
|
option forwardfor
|
|
retries 3
|
|
timeout http-request 30s
|
|
timeout connect 30s
|
|
timeout client 32s
|
|
timeout server 32s
|
|
timeout http-keep-alive 30s
|
|
"""
|
|
|
|
RATE_LIMITED_CONFIG_TEMPLATE = """
|
|
backend base_rate_limiter
|
|
stick-table type %(ip_version)s size 10k expire %(stick_table_expire)ss store http_req_rate(%(base_window_duration)ss)
|
|
|
|
backend burst_rate_limiter
|
|
stick-table type %(ip_version)s size 10k expire %(stick_table_expire)ss store http_req_rate(%(burst_window_duration)ss)
|
|
|
|
listen listener
|
|
bind %(host)s:%(port)s
|
|
%(bind_v6_line)s
|
|
|
|
http-request track-sc0 src table base_rate_limiter
|
|
http-request track-sc1 src table burst_rate_limiter
|
|
http-request deny deny_status 429 if { src_http_req_rate(base_rate_limiter) gt %(base_query_rate_limit)s }
|
|
http-request deny deny_status 429 if { src_http_req_rate(burst_rate_limiter) gt %(burst_query_rate_limit)s }
|
|
|
|
server metadata %(unix_socket_path)s
|
|
""" # noqa: E501 line-length
|
|
|
|
|
|
def parse_ip_versions(ip_versions):
|
|
if not set(ip_versions).issubset({str(constants.IP_VERSION_4),
|
|
str(constants.IP_VERSION_6)}):
|
|
LOG.warning('Invalid metadata address IP versions: %s. Metadata rate '
|
|
'limiting will not be enabled.', ip_versions)
|
|
return
|
|
if len(ip_versions) != 1:
|
|
LOG.warning('Invalid metadata address IP versions: %s. Metadata rate '
|
|
'limiting cannot be enabled for IPv4 and IPv6 at the same '
|
|
'time. Metadata rate limiting will not be enabled.',
|
|
ip_versions)
|
|
return
|
|
return ip_versions[0]
|
|
|
|
|
|
def get_haproxy_config(cfg_info, rate_limiting_config, header_config_template,
|
|
unlimited_config_template):
|
|
ip_version = parse_ip_versions(rate_limiting_config.ip_versions)
|
|
if rate_limiting_config.rate_limit_enabled and ip_version:
|
|
cfg_info['ip_version'] = (
|
|
'ipv6' if ip_version == '6' else 'ip')
|
|
cfg_info['base_window_duration'] = (
|
|
rate_limiting_config['base_window_duration'])
|
|
cfg_info['base_query_rate_limit'] = (
|
|
rate_limiting_config['base_query_rate_limit'])
|
|
cfg_info['burst_window_duration'] = (
|
|
rate_limiting_config['burst_window_duration'])
|
|
cfg_info['burst_query_rate_limit'] = (
|
|
rate_limiting_config['burst_query_rate_limit'])
|
|
cfg_info['stick_table_expire'] = max(
|
|
rate_limiting_config['base_window_duration'],
|
|
rate_limiting_config['burst_window_duration'])
|
|
FINAL_CONFIG_TEMPLATE = (METADATA_HAPROXY_GLOBAL +
|
|
RATE_LIMITED_CONFIG_TEMPLATE +
|
|
header_config_template)
|
|
else:
|
|
FINAL_CONFIG_TEMPLATE = (METADATA_HAPROXY_GLOBAL +
|
|
unlimited_config_template +
|
|
header_config_template)
|
|
|
|
return FINAL_CONFIG_TEMPLATE % cfg_info
|