Merge "UDP jinja template"
This commit is contained in:
commit
babdac52c4
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
nc_cmd=`which nc`
|
||||
$nc_cmd -uzv -w1 $1 $2 > /dev/null
|
||||
exit $?
|
|
@ -31,6 +31,7 @@ HEALTH_MONITOR_TCP = 'TCP'
|
|||
HEALTH_MONITOR_HTTP = 'HTTP'
|
||||
HEALTH_MONITOR_HTTPS = 'HTTPS'
|
||||
HEALTH_MONITOR_TLS_HELLO = 'TLS-HELLO'
|
||||
HEALTH_MONITOR_UDP_CONNECT = 'UDP-CONNECT'
|
||||
SUPPORTED_HEALTH_MONITOR_TYPES = (HEALTH_MONITOR_HTTP, HEALTH_MONITOR_HTTPS,
|
||||
HEALTH_MONITOR_PING, HEALTH_MONITOR_TCP,
|
||||
HEALTH_MONITOR_TLS_HELLO)
|
||||
|
@ -65,6 +66,7 @@ UPDATE_STATS = 'UPDATE_STATS'
|
|||
UPDATE_HEALTH = 'UPDATE_HEALTH'
|
||||
|
||||
PROTOCOL_TCP = 'TCP'
|
||||
PROTOCOL_UDP = 'UDP'
|
||||
PROTOCOL_HTTP = 'HTTP'
|
||||
PROTOCOL_HTTPS = 'HTTPS'
|
||||
PROTOCOL_TERMINATED_HTTPS = 'TERMINATED_HTTPS'
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
# Copyright (c) 2018 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
|
||||
import os
|
||||
|
||||
import jinja2
|
||||
|
||||
from octavia.common.config import cfg
|
||||
from octavia.common import constants
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
PROTOCOL_MAP = {
|
||||
constants.PROTOCOL_UDP: 'udp'
|
||||
}
|
||||
|
||||
BALANCE_MAP = {
|
||||
constants.LB_ALGORITHM_ROUND_ROBIN: 'rr',
|
||||
constants.LB_ALGORITHM_LEAST_CONNECTIONS: 'lc',
|
||||
constants.LB_ALGORITHM_SOURCE_IP: 'sh'
|
||||
}
|
||||
|
||||
BASE_PATH = CONF.haproxy_amphora.base_path
|
||||
|
||||
CHECK_SCRIPT_NAME = 'udp_check.sh'
|
||||
|
||||
KEEPALIVED_LVS_TEMPLATE = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__),
|
||||
'templates/keepalivedlvs.cfg.j2'))
|
||||
|
||||
JINJA_ENV = None
|
||||
|
||||
|
||||
class LvsJinjaTemplater(object):
|
||||
|
||||
def __init__(self, base_amp_path=None, keepalivedlvs_template=None):
|
||||
"""Keepalived LVS configuration generation
|
||||
|
||||
:param base_amp_path: Base path for amphora data
|
||||
:param keepalivedlvs_template: Absolute path to Jinja template
|
||||
"""
|
||||
|
||||
self.base_amp_path = base_amp_path or BASE_PATH
|
||||
self.keepalivedlvs_template = (keepalivedlvs_template or
|
||||
KEEPALIVED_LVS_TEMPLATE)
|
||||
|
||||
def build_config(self, listener, **kwargs):
|
||||
"""Convert a logical configuration to the Keepalived LVS version
|
||||
|
||||
:param listener: The listener configuration
|
||||
:return: Rendered configuration
|
||||
"""
|
||||
return self.render_loadbalancer_obj(listener)
|
||||
|
||||
def _get_template(self):
|
||||
"""Returns the specified Jinja configuration template."""
|
||||
global JINJA_ENV
|
||||
if not JINJA_ENV:
|
||||
template_loader = jinja2.FileSystemLoader(
|
||||
searchpath=os.path.dirname(self.keepalivedlvs_template))
|
||||
JINJA_ENV = jinja2.Environment(
|
||||
autoescape=True,
|
||||
loader=template_loader,
|
||||
trim_blocks=True,
|
||||
lstrip_blocks=True,
|
||||
extensions=['jinja2.ext.do'])
|
||||
return JINJA_ENV.get_template(os.path.basename(
|
||||
self.keepalivedlvs_template))
|
||||
|
||||
def render_loadbalancer_obj(self, listener, **kwargs):
|
||||
"""Renders a templated configuration from a load balancer object
|
||||
|
||||
:param host_amphora: The Amphora this configuration is hosted on
|
||||
:param listener: The listener configuration
|
||||
:return: Rendered configuration
|
||||
"""
|
||||
loadbalancer = self._transform_loadbalancer(
|
||||
listener.load_balancer,
|
||||
listener)
|
||||
return self._get_template().render(
|
||||
{'loadbalancer': loadbalancer},
|
||||
constants=constants)
|
||||
|
||||
def _transform_loadbalancer(self, loadbalancer, listener):
|
||||
"""Transforms a load balancer into an object that will
|
||||
|
||||
be processed by the templating system
|
||||
"""
|
||||
t_listener = self._transform_listener(listener)
|
||||
ret_value = {
|
||||
'vip_address': loadbalancer.vip.ip_address,
|
||||
'listener': t_listener,
|
||||
'enabled': loadbalancer.enabled
|
||||
}
|
||||
return ret_value
|
||||
|
||||
def _transform_listener(self, listener):
|
||||
"""Transforms a listener into an object that will
|
||||
|
||||
be processed by the templating system
|
||||
"""
|
||||
ret_value = {
|
||||
'id': listener.id,
|
||||
'protocol_port': listener.protocol_port,
|
||||
'protocol_mode': PROTOCOL_MAP[listener.protocol],
|
||||
'enabled': listener.enabled
|
||||
}
|
||||
if listener.connection_limit and listener.connection_limit > -1:
|
||||
ret_value['connection_limit'] = listener.connection_limit
|
||||
if listener.default_pool:
|
||||
ret_value['default_pool'] = self._transform_pool(
|
||||
listener.default_pool)
|
||||
return ret_value
|
||||
|
||||
def _transform_pool(self, pool):
|
||||
"""Transforms a pool into an object that will
|
||||
|
||||
be processed by the templating system
|
||||
"""
|
||||
ret_value = {
|
||||
'id': pool.id,
|
||||
'protocol': PROTOCOL_MAP[pool.protocol],
|
||||
'lb_algorithm': BALANCE_MAP.get(pool.lb_algorithm,
|
||||
'roundrobin'),
|
||||
'members': [],
|
||||
'health_monitor': '',
|
||||
'session_persistence': '',
|
||||
'enabled': pool.enabled
|
||||
}
|
||||
members = [self._transform_member(x) for x in pool.members]
|
||||
ret_value['members'] = members
|
||||
if pool.health_monitor:
|
||||
ret_value['health_monitor'] = self._transform_health_monitor(
|
||||
pool.health_monitor)
|
||||
if pool.session_persistence:
|
||||
func = self._transform_session_persistence
|
||||
ret_value['session_persistence'] = func(
|
||||
pool.session_persistence)
|
||||
return ret_value
|
||||
|
||||
@staticmethod
|
||||
def _transform_session_persistence(persistence):
|
||||
"""Transforms session persistence into an object that will
|
||||
|
||||
be processed by the templating system
|
||||
"""
|
||||
return {
|
||||
'type': persistence.type,
|
||||
'persistence_timeout': persistence.persistence_timeout,
|
||||
'persistence_granularity': persistence.persistence_granularity
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _transform_member(member):
|
||||
"""Transforms a member into an object that will
|
||||
|
||||
be processed by the templating system
|
||||
"""
|
||||
return {
|
||||
'id': member.id,
|
||||
'address': member.ip_address,
|
||||
'protocol_port': member.protocol_port,
|
||||
'weight': member.weight,
|
||||
'enabled': member.enabled
|
||||
}
|
||||
|
||||
def _get_default_lvs_check_script_path(self):
|
||||
return (CONF.haproxy_amphora.base_path +
|
||||
'/lvs/check/' + CHECK_SCRIPT_NAME)
|
||||
|
||||
def _transform_health_monitor(self, monitor):
|
||||
"""Transforms a health monitor into an object that will
|
||||
|
||||
be processed by the templating system
|
||||
"""
|
||||
return {
|
||||
'id': monitor.id,
|
||||
'type': monitor.type,
|
||||
'delay': monitor.delay,
|
||||
'timeout': monitor.timeout,
|
||||
'enabled': monitor.enabled,
|
||||
'fall_threshold': monitor.fall_threshold,
|
||||
'check_script_path': (self._get_default_lvs_check_script_path()
|
||||
if monitor.type ==
|
||||
constants.HEALTH_MONITOR_UDP_CONNECT else
|
||||
None)
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{# Copyright (c) 2018 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#}
|
||||
# Configuration for Listener {{ udp_listener_id }}
|
||||
|
||||
{% block global_definitions %}{% endblock global_definitions %}
|
||||
|
||||
{% block proxies %}{% endblock proxies %}
|
|
@ -0,0 +1,28 @@
|
|||
{# Copyright (c) 2018 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#}
|
||||
{% extends 'base.j2' %}
|
||||
{% from 'macros.j2' import virtualserver_macro %}
|
||||
{% set udp_listener_id = loadbalancer.listener.id %}
|
||||
{% block global_definitions %}
|
||||
net_namespace amphora-haproxy
|
||||
{% endblock global_definitions %}
|
||||
{% block proxies %}
|
||||
{% if loadbalancer.enabled and loadbalancer.listener.enabled %}
|
||||
{{- virtualserver_macro(constants, loadbalancer.listener,
|
||||
loadbalancer.vip_address,
|
||||
loadbalancer.listener.get('default_pool', None)) }}
|
||||
{% endif %}
|
||||
{% endblock proxies %}
|
|
@ -0,0 +1,105 @@
|
|||
{# Copyright (c) 2018 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#}
|
||||
|
||||
{%- macro lb_algo_macro(pool) -%}
|
||||
lb_algo {{ pool.lb_algorithm }}
|
||||
{%- endmacro -%}
|
||||
|
||||
{% macro misc_path_macro(member, health_monitor) -%}
|
||||
misc_path "{{ health_monitor.check_script_path }} {{ member.address }} {{ member.protocol_port }}"
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro misc_check_macro(pool, member, health_monitor) -%}
|
||||
MISC_CHECK {
|
||||
{{ misc_path_macro(member, health_monitor) }}
|
||||
misc_timeout {{ pool.health_monitor.delay }}
|
||||
misc_dynamic
|
||||
}
|
||||
{%- endmacro -%}
|
||||
|
||||
{% macro health_monitor_rs_macro(constants, pool, member) %}
|
||||
{% if pool.health_monitor and pool.health_monitor.enabled %}
|
||||
{% if pool.health_monitor.timeout %}
|
||||
delay_before_retry {{ pool.health_monitor.timeout }}
|
||||
{% endif %}
|
||||
{% if pool.health_monitor.fall_threshold %}
|
||||
retry {{ pool.health_monitor.fall_threshold }}
|
||||
{% endif %}
|
||||
{% if pool.health_monitor.type == constants.HEALTH_MONITOR_UDP_CONNECT %}
|
||||
{{ misc_check_macro(pool, member, pool.health_monitor) -}}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro realserver_macro(constants, pool, member, listener) %}
|
||||
# Configuration for Member {{ member.id }}
|
||||
real_server {{ member.address }} {{ member.protocol_port }} {
|
||||
weight {{ member.weight }}
|
||||
inhibit_on_failure
|
||||
{% if listener.connection_limit %}
|
||||
uthreshold {{ listener.connection_limit }}
|
||||
{% endif %}
|
||||
{% if pool.session_persistence and pool.session_persistence.type == constants.SESSION_PERSISTENCE_SOURCE_IP %}
|
||||
persistence_timeout {{ pool.session_persistence.persistence_timeout }}
|
||||
persistence_granularity {{ pool.session_persistence.persistence_granularity }}
|
||||
{% endif %}
|
||||
{{- health_monitor_rs_macro(constants, pool, member) }}
|
||||
}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro health_monitor_vs_macro(default_pool) %}
|
||||
{% if default_pool and default_pool.health_monitor and default_pool.health_monitor.enabled %}
|
||||
{% if default_pool.health_monitor.delay %}
|
||||
delay_loop {{ default_pool.health_monitor.delay }}
|
||||
{% endif %}
|
||||
{% if default_pool.health_monitor.timeout %}
|
||||
delay_before_retry {{ default_pool.health_monitor.timeout }}
|
||||
{% endif %}
|
||||
{% if default_pool.health_monitor.fall_threshold %}
|
||||
retry {{ default_pool.health_monitor.fall_threshold }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro virtualserver_macro(constants, listener, lb_vip_address, default_pool) %}
|
||||
{% set need_render = [] %}
|
||||
{% if default_pool and default_pool.enabled and default_pool.members %}
|
||||
{% for member in default_pool.members if member.enabled %}
|
||||
{% do need_render.append(member.enabled) %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if need_render|length > 0 %}
|
||||
virtual_server {{ lb_vip_address }} {{ listener.protocol_port }} {
|
||||
{{ lb_algo_macro(default_pool) }}
|
||||
{% if not default_pool.session_persistence %}
|
||||
ops
|
||||
{% endif %}
|
||||
lb_kind NAT
|
||||
protocol {{ listener.protocol_mode }}
|
||||
{{ health_monitor_vs_macro(default_pool) }}
|
||||
|
||||
{% if default_pool.protocol.lower() == "udp" %}
|
||||
# Configuration for Pool {{ default_pool.id }}
|
||||
{% if default_pool.health_monitor and default_pool.health_monitor.enabled %}
|
||||
# Configuration for HealthMonitor {{ default_pool.health_monitor.id }}
|
||||
{% endif %}
|
||||
{% for member in default_pool.members if member.enabled %}
|
||||
{{- realserver_macro(constants, default_pool, member, listener) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
|
@ -0,0 +1,270 @@
|
|||
# Copyright 2018 OpenStack Foundation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 octavia.common import constants
|
||||
from octavia.common.jinja.lvs import jinja_cfg
|
||||
from octavia.tests.unit import base
|
||||
from octavia.tests.unit.common.sample_configs import sample_configs
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_config import fixture as oslo_fixture
|
||||
|
||||
BASE_PATH = '/var/lib/octavia'
|
||||
|
||||
|
||||
class TestLvsCfg(base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestLvsCfg, self).setUp()
|
||||
self.udp_jinja_cfg = jinja_cfg.LvsJinjaTemplater()
|
||||
conf = oslo_fixture.Config(cfg.CONF)
|
||||
conf.config(group="haproxy_amphora", base_path=BASE_PATH)
|
||||
|
||||
def test_udp_get_template(self):
|
||||
template = self.udp_jinja_cfg._get_template()
|
||||
self.assertEqual('keepalivedlvs.cfg.j2', template.name)
|
||||
|
||||
def test_render_template_udp_source_ip(self):
|
||||
exp = ("# Configuration for Listener sample_listener_id_1\n\n"
|
||||
"net_namespace amphora-haproxy\n\n"
|
||||
"virtual_server 10.0.0.2 80 {\n"
|
||||
" lb_algo rr\n"
|
||||
" lb_kind NAT\n"
|
||||
" protocol udp\n"
|
||||
" delay_loop 30\n"
|
||||
" delay_before_retry 31\n"
|
||||
" retry 3\n\n\n"
|
||||
" # Configuration for Pool sample_pool_id_1\n"
|
||||
" # Configuration for HealthMonitor sample_monitor_id_1\n"
|
||||
" # Configuration for Member sample_member_id_1\n"
|
||||
" real_server 10.0.0.99 82 {\n"
|
||||
" weight 13\n"
|
||||
" inhibit_on_failure\n"
|
||||
" uthreshold 98\n"
|
||||
" persistence_timeout 33\n"
|
||||
" persistence_granularity 255.255.0.0\n"
|
||||
" delay_before_retry 31\n"
|
||||
" retry 3\n"
|
||||
" MISC_CHECK {\n"
|
||||
" misc_path \"/var/lib/octavia/lvs/check/"
|
||||
"udp_check.sh 10.0.0.99 82\"\n"
|
||||
" misc_timeout 30\n"
|
||||
" misc_dynamic\n"
|
||||
" }\n"
|
||||
" }\n\n"
|
||||
" # Configuration for Member sample_member_id_2\n"
|
||||
" real_server 10.0.0.98 82 {\n"
|
||||
" weight 13\n"
|
||||
" inhibit_on_failure\n"
|
||||
" uthreshold 98\n"
|
||||
" persistence_timeout 33\n"
|
||||
" persistence_granularity 255.255.0.0\n"
|
||||
" delay_before_retry 31\n"
|
||||
" retry 3\n"
|
||||
" MISC_CHECK {\n"
|
||||
" misc_path \"/var/lib/octavia/lvs/check/"
|
||||
"udp_check.sh 10.0.0.98 82\"\n"
|
||||
" misc_timeout 30\n"
|
||||
" misc_dynamic\n"
|
||||
" }\n"
|
||||
" }\n\n"
|
||||
"}\n\n")
|
||||
rendered_obj = self.udp_jinja_cfg.render_loadbalancer_obj(
|
||||
sample_configs.sample_listener_tuple(
|
||||
proto=constants.PROTOCOL_UDP,
|
||||
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||
persistence_timeout=33,
|
||||
persistence_granularity='255.255.0.0',
|
||||
monitor_proto=constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
connection_limit=98))
|
||||
self.assertEqual(exp, rendered_obj)
|
||||
|
||||
def test_render_template_udp_one_packet(self):
|
||||
exp = ("# Configuration for Listener sample_listener_id_1\n\n"
|
||||
"net_namespace amphora-haproxy\n\n"
|
||||
"virtual_server 10.0.0.2 80 {\n"
|
||||
" lb_algo rr\n"
|
||||
" ops\n"
|
||||
" lb_kind NAT\n"
|
||||
" protocol udp\n"
|
||||
" delay_loop 30\n"
|
||||
" delay_before_retry 31\n"
|
||||
" retry 3\n\n\n"
|
||||
" # Configuration for Pool sample_pool_id_1\n"
|
||||
" # Configuration for HealthMonitor sample_monitor_id_1\n"
|
||||
" # Configuration for Member sample_member_id_1\n"
|
||||
" real_server 10.0.0.99 82 {\n"
|
||||
" weight 13\n"
|
||||
" inhibit_on_failure\n"
|
||||
" uthreshold 98\n"
|
||||
" delay_before_retry 31\n"
|
||||
" retry 3\n"
|
||||
" MISC_CHECK {\n"
|
||||
" misc_path \"/var/lib/octavia/lvs/check/"
|
||||
"udp_check.sh 10.0.0.99 82\"\n"
|
||||
" misc_timeout 30\n"
|
||||
" misc_dynamic\n"
|
||||
" }\n"
|
||||
" }\n\n"
|
||||
" # Configuration for Member sample_member_id_2\n"
|
||||
" real_server 10.0.0.98 82 {\n"
|
||||
" weight 13\n"
|
||||
" inhibit_on_failure\n"
|
||||
" uthreshold 98\n"
|
||||
" delay_before_retry 31\n"
|
||||
" retry 3\n"
|
||||
" MISC_CHECK {\n"
|
||||
" misc_path \"/var/lib/octavia/lvs/check/"
|
||||
"udp_check.sh 10.0.0.98 82\"\n"
|
||||
" misc_timeout 30\n"
|
||||
" misc_dynamic\n"
|
||||
" }\n"
|
||||
" }\n\n"
|
||||
"}\n\n")
|
||||
|
||||
listener = sample_configs.sample_listener_tuple(
|
||||
proto=constants.PROTOCOL_UDP,
|
||||
monitor_proto=constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
connection_limit=98,
|
||||
persistence=False)
|
||||
rendered_obj = self.udp_jinja_cfg.render_loadbalancer_obj(listener)
|
||||
self.assertEqual(exp, rendered_obj)
|
||||
|
||||
def test_render_template_udp_with_health_monitor(self):
|
||||
exp = ("# Configuration for Listener sample_listener_id_1\n\n"
|
||||
"net_namespace amphora-haproxy\n\n"
|
||||
"virtual_server 10.0.0.2 80 {\n"
|
||||
" lb_algo rr\n"
|
||||
" ops\n"
|
||||
" lb_kind NAT\n"
|
||||
" protocol udp\n"
|
||||
" delay_loop 30\n"
|
||||
" delay_before_retry 31\n"
|
||||
" retry 3\n\n\n"
|
||||
" # Configuration for Pool sample_pool_id_1\n"
|
||||
" # Configuration for HealthMonitor sample_monitor_id_1\n"
|
||||
" # Configuration for Member sample_member_id_1\n"
|
||||
" real_server 10.0.0.99 82 {\n"
|
||||
" weight 13\n"
|
||||
" inhibit_on_failure\n"
|
||||
" uthreshold 98\n"
|
||||
" delay_before_retry 31\n"
|
||||
" retry 3\n"
|
||||
" MISC_CHECK {\n"
|
||||
" misc_path \"/var/lib/octavia/lvs/check/"
|
||||
"udp_check.sh 10.0.0.99 82\"\n"
|
||||
" misc_timeout 30\n"
|
||||
" misc_dynamic\n"
|
||||
" }\n"
|
||||
" }\n\n"
|
||||
" # Configuration for Member sample_member_id_2\n"
|
||||
" real_server 10.0.0.98 82 {\n"
|
||||
" weight 13\n"
|
||||
" inhibit_on_failure\n"
|
||||
" uthreshold 98\n"
|
||||
" delay_before_retry 31\n"
|
||||
" retry 3\n"
|
||||
" MISC_CHECK {\n"
|
||||
" misc_path \"/var/lib/octavia/lvs/check/"
|
||||
"udp_check.sh 10.0.0.98 82\"\n"
|
||||
" misc_timeout 30\n"
|
||||
" misc_dynamic\n"
|
||||
" }\n"
|
||||
" }\n\n"
|
||||
"}\n\n")
|
||||
|
||||
rendered_obj = self.udp_jinja_cfg.render_loadbalancer_obj(
|
||||
sample_configs.sample_listener_tuple(
|
||||
proto=constants.PROTOCOL_UDP,
|
||||
monitor_proto=constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
persistence=False,
|
||||
connection_limit=98))
|
||||
self.assertEqual(exp, rendered_obj)
|
||||
|
||||
def test_render_template_udp_no_other_resources(self):
|
||||
exp = ("# Configuration for Listener sample_listener_id_1\n\n"
|
||||
"net_namespace amphora-haproxy\n\n\n")
|
||||
|
||||
rendered_obj = self.udp_jinja_cfg.render_loadbalancer_obj(
|
||||
sample_configs.sample_listener_tuple(
|
||||
proto=constants.PROTOCOL_UDP, monitor=False,
|
||||
persistence=False, alloc_default_pool=False))
|
||||
self.assertEqual(exp, rendered_obj)
|
||||
|
||||
def test_udp_transform_session_persistence(self):
|
||||
persistence_src_ip = sample_configs.sample_session_persistence_tuple(
|
||||
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||
persistence_cookie=None,
|
||||
persistence_timeout=33,
|
||||
persistence_granularity='255.0.0.0'
|
||||
)
|
||||
exp = sample_configs.UDP_SOURCE_IP_BODY
|
||||
ret = self.udp_jinja_cfg._transform_session_persistence(
|
||||
persistence_src_ip)
|
||||
self.assertEqual(exp, ret)
|
||||
|
||||
def test_udp_transform_health_monitor(self):
|
||||
in_hm = sample_configs.sample_health_monitor_tuple(
|
||||
proto=constants.HEALTH_MONITOR_UDP_CONNECT
|
||||
)
|
||||
ret = self.udp_jinja_cfg._transform_health_monitor(in_hm)
|
||||
self.assertEqual(sample_configs.RET_UDP_HEALTH_MONITOR, ret)
|
||||
|
||||
def test_udp_transform_member(self):
|
||||
in_member = sample_configs.sample_member_tuple('member_id_1',
|
||||
'192.0.2.10')
|
||||
ret = self.udp_jinja_cfg._transform_member(in_member)
|
||||
self.assertEqual(sample_configs.RET_UDP_MEMBER, ret)
|
||||
|
||||
def test_udp_transform_pool(self):
|
||||
in_pool = sample_configs.sample_pool_tuple(
|
||||
proto=constants.PROTOCOL_UDP,
|
||||
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||
persistence_timeout=33, persistence_granularity='255.0.0.0',
|
||||
)
|
||||
ret = self.udp_jinja_cfg._transform_pool(in_pool)
|
||||
self.assertEqual(sample_configs.RET_UDP_POOL, ret)
|
||||
|
||||
in_pool = sample_configs.sample_pool_tuple(
|
||||
proto=constants.PROTOCOL_UDP,
|
||||
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||
persistence_timeout=33, persistence_granularity='255.0.0.0',
|
||||
monitor=False)
|
||||
sample_configs.RET_UDP_POOL['health_monitor'] = ''
|
||||
ret = self.udp_jinja_cfg._transform_pool(in_pool)
|
||||
self.assertEqual(sample_configs.RET_UDP_POOL, ret)
|
||||
|
||||
def test_udp_transform_listener(self):
|
||||
in_listener = sample_configs.sample_listener_tuple(
|
||||
proto=constants.PROTOCOL_UDP,
|
||||
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||
persistence_timeout=33,
|
||||
persistence_granularity='255.0.0.0',
|
||||
monitor_proto=constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
connection_limit=98
|
||||
)
|
||||
ret = self.udp_jinja_cfg._transform_listener(in_listener)
|
||||
self.assertEqual(sample_configs.RET_UDP_LISTENER, ret)
|
||||
|
||||
in_listener = sample_configs.sample_listener_tuple(
|
||||
proto=constants.PROTOCOL_UDP,
|
||||
persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||
persistence_timeout=33,
|
||||
persistence_granularity='255.0.0.0',
|
||||
monitor_proto=constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
connection_limit=-1)
|
||||
|
||||
ret = self.udp_jinja_cfg._transform_listener(in_listener)
|
||||
sample_configs.RET_UDP_LISTENER.pop('connection_limit')
|
||||
self.assertEqual(sample_configs.RET_UDP_LISTENER, ret)
|
|
@ -15,10 +15,13 @@
|
|||
|
||||
import collections
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from octavia.common import constants
|
||||
from octavia.tests.unit.common.sample_configs import sample_certs
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def sample_amphora_tuple():
|
||||
in_amphora = collections.namedtuple(
|
||||
|
@ -336,6 +339,84 @@ RET_LB_L7 = {
|
|||
'enabled': True,
|
||||
'global_connection_limit': constants.HAPROXY_MAX_MAXCONN}
|
||||
|
||||
UDP_SOURCE_IP_BODY = {
|
||||
'type': constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||
'persistence_timeout': 33,
|
||||
'persistence_granularity': '255.0.0.0'
|
||||
}
|
||||
|
||||
RET_UDP_HEALTH_MONITOR = {
|
||||
'id': 'sample_monitor_id_1',
|
||||
'type': constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
'delay': 30,
|
||||
'timeout': 31,
|
||||
'enabled': True,
|
||||
'fall_threshold': 3,
|
||||
'check_script_path': (CONF.haproxy_amphora.base_path +
|
||||
'/lvs/check/udp_check.sh')
|
||||
}
|
||||
|
||||
UDP_HEALTH_MONITOR_NO_SCRIPT = {
|
||||
'id': 'sample_monitor_id_1',
|
||||
'check_script_path': None,
|
||||
'delay': 30,
|
||||
'enabled': True,
|
||||
'fall_threshold': 3,
|
||||
'timeout': 31,
|
||||
'type': 'UDP'
|
||||
}
|
||||
|
||||
RET_UDP_MEMBER = {
|
||||
'id': 'member_id_1',
|
||||
'address': '192.0.2.10',
|
||||
'protocol_port': 82,
|
||||
'weight': 13,
|
||||
'enabled': True
|
||||
}
|
||||
|
||||
UDP_MEMBER_1 = {
|
||||
'id': 'sample_member_id_1',
|
||||
'address': '10.0.0.99',
|
||||
'enabled': True,
|
||||
'protocol_port': 82,
|
||||
'weight': 13
|
||||
}
|
||||
|
||||
UDP_MEMBER_2 = {
|
||||
'id': 'sample_member_id_2',
|
||||
'address': '10.0.0.98',
|
||||
'enabled': True,
|
||||
'protocol_port': 82,
|
||||
'weight': 13
|
||||
}
|
||||
|
||||
RET_UDP_POOL = {
|
||||
'id': 'sample_pool_id_1',
|
||||
'enabled': True,
|
||||
'health_monitor': UDP_HEALTH_MONITOR_NO_SCRIPT,
|
||||
'lb_algorithm': 'rr',
|
||||
'members': [UDP_MEMBER_1, UDP_MEMBER_2],
|
||||
'protocol': 'udp',
|
||||
'session_persistence': UDP_SOURCE_IP_BODY
|
||||
}
|
||||
|
||||
RET_UDP_LISTENER = {
|
||||
'connection_limit': 98,
|
||||
'default_pool': {
|
||||
'id': 'sample_pool_id_1',
|
||||
'enabled': True,
|
||||
'health_monitor': RET_UDP_HEALTH_MONITOR,
|
||||
'lb_algorithm': 'rr',
|
||||
'members': [UDP_MEMBER_1, UDP_MEMBER_2],
|
||||
'protocol': 'udp',
|
||||
'session_persistence': UDP_SOURCE_IP_BODY
|
||||
},
|
||||
'enabled': True,
|
||||
'id': 'sample_listener_id_1',
|
||||
'protocol_mode': 'udp',
|
||||
'protocol_port': '80'
|
||||
}
|
||||
|
||||
|
||||
def sample_loadbalancer_tuple(proto=None, monitor=True, persistence=True,
|
||||
persistence_type=None, tls=False, sni=False,
|
||||
|
@ -400,8 +481,10 @@ def sample_vip_tuple():
|
|||
return vip(ip_address='10.0.0.2')
|
||||
|
||||
|
||||
def sample_listener_tuple(proto=None, monitor=True, persistence=True,
|
||||
persistence_type=None, persistence_cookie=None,
|
||||
def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
|
||||
persistence=True, persistence_type=None,
|
||||
persistence_cookie=None, persistence_timeout=None,
|
||||
persistence_granularity=None,
|
||||
tls=False, sni=False, peer_port=None, topology=None,
|
||||
l7=False, enabled=True, insert_headers=None,
|
||||
be_proto=None, monitor_ip_port=False,
|
||||
|
@ -466,7 +549,10 @@ def sample_listener_tuple(proto=None, monitor=True, persistence=True,
|
|||
proto=be_proto, monitor=monitor, persistence=persistence,
|
||||
persistence_type=persistence_type,
|
||||
persistence_cookie=persistence_cookie,
|
||||
monitor_ip_port=monitor_ip_port, monitor_proto=monitor_proto),
|
||||
persistence_timeout=persistence_timeout,
|
||||
persistence_granularity=persistence_granularity,
|
||||
monitor_ip_port=monitor_ip_port,
|
||||
monitor_proto=monitor_proto) if alloc_default_pool else '',
|
||||
connection_limit=connection_limit,
|
||||
tls_certificate_id='cont_id_1' if tls else '',
|
||||
sni_container_ids=['cont_id_2', 'cont_id_3'] if sni else [],
|
||||
|
@ -527,6 +613,7 @@ def sample_tls_container_tuple(id='cont_id_1', certificate=None,
|
|||
|
||||
def sample_pool_tuple(proto=None, monitor=True, persistence=True,
|
||||
persistence_type=None, persistence_cookie=None,
|
||||
persistence_timeout=None, persistence_granularity=None,
|
||||
sample_pool=1, monitor_ip_port=False,
|
||||
monitor_proto=None, backup_member=False,
|
||||
disabled_member=False):
|
||||
|
@ -535,9 +622,15 @@ def sample_pool_tuple(proto=None, monitor=True, persistence=True,
|
|||
in_pool = collections.namedtuple(
|
||||
'pool', 'id, protocol, lb_algorithm, members, health_monitor,'
|
||||
'session_persistence, enabled, operating_status')
|
||||
persis = sample_session_persistence_tuple(
|
||||
persistence_type=persistence_type,
|
||||
persistence_cookie=persistence_cookie) if persistence is True else None
|
||||
if (proto == constants.PROTOCOL_UDP and
|
||||
persistence_type == constants.SESSION_PERSISTENCE_SOURCE_IP):
|
||||
kwargs = {'persistence_type': persistence_type,
|
||||
'persistence_timeout': persistence_timeout,
|
||||
'persistence_granularity': persistence_granularity}
|
||||
else:
|
||||
kwargs = {'persistence_type': persistence_type,
|
||||
'persistence_cookie': persistence_cookie}
|
||||
persis = sample_session_persistence_tuple(**kwargs)
|
||||
mon = None
|
||||
if sample_pool == 1:
|
||||
id = 'sample_pool_id_1'
|
||||
|
@ -561,7 +654,7 @@ def sample_pool_tuple(proto=None, monitor=True, persistence=True,
|
|||
lb_algorithm='ROUND_ROBIN',
|
||||
members=members,
|
||||
health_monitor=mon,
|
||||
session_persistence=persis,
|
||||
session_persistence=persis if persistence is True else None,
|
||||
enabled=True,
|
||||
operating_status='ACTIVE')
|
||||
|
||||
|
@ -590,19 +683,26 @@ def sample_member_tuple(id, ip, enabled=True, operating_status='ACTIVE',
|
|||
|
||||
|
||||
def sample_session_persistence_tuple(persistence_type=None,
|
||||
persistence_cookie=None):
|
||||
persistence_cookie=None,
|
||||
persistence_timeout=None,
|
||||
persistence_granularity=None):
|
||||
spersistence = collections.namedtuple('SessionPersistence',
|
||||
'type, cookie_name')
|
||||
'type, cookie_name, '
|
||||
'persistence_timeout, '
|
||||
'persistence_granularity')
|
||||
pt = 'HTTP_COOKIE' if persistence_type is None else persistence_type
|
||||
return spersistence(type=pt,
|
||||
cookie_name=persistence_cookie)
|
||||
cookie_name=persistence_cookie,
|
||||
persistence_timeout=persistence_timeout,
|
||||
persistence_granularity=persistence_granularity)
|
||||
|
||||
|
||||
def sample_health_monitor_tuple(proto='HTTP', sample_hm=1):
|
||||
proto = 'HTTP' if proto is 'TERMINATED_HTTPS' else proto
|
||||
monitor = collections.namedtuple(
|
||||
'monitor', 'id, type, delay, timeout, fall_threshold, rise_threshold,'
|
||||
'http_method, url_path, expected_codes, enabled')
|
||||
'http_method, url_path, expected_codes, enabled, '
|
||||
'check_script_path')
|
||||
|
||||
if sample_hm == 1:
|
||||
id = 'sample_monitor_id_1'
|
||||
|
@ -610,10 +710,24 @@ def sample_health_monitor_tuple(proto='HTTP', sample_hm=1):
|
|||
elif sample_hm == 2:
|
||||
id = 'sample_monitor_id_2'
|
||||
url_path = '/healthmon.html'
|
||||
return monitor(id=id, type=proto, delay=30,
|
||||
timeout=31, fall_threshold=3, rise_threshold=2,
|
||||
http_method='GET', url_path=url_path,
|
||||
expected_codes='418', enabled=True)
|
||||
kwargs = {
|
||||
'id': id,
|
||||
'type': proto,
|
||||
'delay': 30,
|
||||
'timeout': 31,
|
||||
'fall_threshold': 3,
|
||||
'rise_threshold': 2,
|
||||
'http_method': 'GET',
|
||||
'url_path': url_path,
|
||||
'expected_codes': '418',
|
||||
'enabled': True
|
||||
}
|
||||
if proto == constants.HEALTH_MONITOR_UDP_CONNECT:
|
||||
kwargs['check_script_path'] = (CONF.haproxy_amphora.base_path +
|
||||
'lvs/check/' + 'udp_check.sh')
|
||||
else:
|
||||
kwargs['check_script_path'] = None
|
||||
return monitor(**kwargs)
|
||||
|
||||
|
||||
def sample_l7policy_tuple(id,
|
||||
|
|
Loading…
Reference in New Issue