Jinja Haproxy templates
Adds Jinja templating for haproxy configuration Adds tests to verify Jinja templating Change-Id: I7dd71bec3d4993ffb732dcd316b801498329fd2a Partially-Implements: bp/haproxy-amphora-driver
This commit is contained in:
parent
10e3fb0f69
commit
847a25042e
0
octavia/amphorae/drivers/haproxy/jinja/__init__.py
Normal file
0
octavia/amphorae/drivers/haproxy/jinja/__init__.py
Normal file
245
octavia/amphorae/drivers/haproxy/jinja/jinja_cfg.py
Normal file
245
octavia/amphorae/drivers/haproxy/jinja/jinja_cfg.py
Normal file
@ -0,0 +1,245 @@
|
||||
# Copyright (c) 2015 Rackspace
|
||||
#
|
||||
# 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
|
||||
import six
|
||||
|
||||
from octavia.common import constants
|
||||
|
||||
PROTOCOL_MAP = {
|
||||
constants.PROTOCOL_TCP: 'tcp',
|
||||
constants.PROTOCOL_HTTP: 'http',
|
||||
constants.PROTOCOL_HTTPS: 'tcp',
|
||||
constants.PROTOCOL_TERMINATED_HTTPS: 'http'
|
||||
}
|
||||
|
||||
BALANCE_MAP = {
|
||||
constants.LB_ALGORITHM_ROUND_ROBIN: 'roundrobin',
|
||||
constants.LB_ALGORITHM_LEAST_CONNECTIONS: 'leastconn',
|
||||
constants.LB_ALGORITHM_SOURCE_IP: 'source'
|
||||
}
|
||||
|
||||
ACTIVE_PENDING_STATUSES = constants.SUPPORTED_PROVISIONING_STATUSES + (
|
||||
constants.DEGRADED,)
|
||||
|
||||
BASE_PATH = '/var/lib/octavia'
|
||||
BASE_CRT_DIR = '/listeners'
|
||||
|
||||
HAPROXY_TEMPLATE = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__),
|
||||
'templates/haproxy_listener.template'))
|
||||
|
||||
JINJA_ENV = None
|
||||
|
||||
|
||||
class JinjaTemplater(object):
|
||||
|
||||
def __init__(self, base_amp_path=None,
|
||||
base_crt_dir=None,
|
||||
haproxy_template=None):
|
||||
|
||||
""":param base_amp_path: Base path for amphora data
|
||||
|
||||
:param base_crt_dir: Base directory for certificate storage
|
||||
|
||||
:param haproxy_template: Absolute path to the Jinja template for
|
||||
|
||||
HaProxy configuration generation
|
||||
|
||||
"""
|
||||
|
||||
self.base_amp_path = base_amp_path if base_amp_path else BASE_PATH
|
||||
self.base_crt_dir = base_crt_dir if base_crt_dir else BASE_CRT_DIR
|
||||
self.haproxy_template = (haproxy_template if haproxy_template
|
||||
else HAPROXY_TEMPLATE)
|
||||
self.cert_store_path = '{0}{1}'.format(self.base_amp_path,
|
||||
self.base_crt_dir)
|
||||
|
||||
def build_config(self, listener, tls_cert,
|
||||
socket_path=None,
|
||||
user_group='nogroup'):
|
||||
"""Convert a logical configuration to the HAProxy version."""
|
||||
return self.render_loadbalancer_obj(listener,
|
||||
tls_cert=tls_cert,
|
||||
user_group=user_group,
|
||||
socket_path=socket_path)
|
||||
|
||||
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.haproxy_template))
|
||||
JINJA_ENV = jinja2.Environment(
|
||||
loader=template_loader,
|
||||
trim_blocks=True,
|
||||
lstrip_blocks=True)
|
||||
return JINJA_ENV.get_template(os.path.basename(self.haproxy_template))
|
||||
|
||||
def render_loadbalancer_obj(self, listener,
|
||||
tls_cert=None,
|
||||
user_group='nogroup',
|
||||
socket_path=None):
|
||||
"""Renders a templated configuration from a load balancer object."""
|
||||
loadbalancer = self._transform_loadbalancer(
|
||||
listener.loadbalancer,
|
||||
listener,
|
||||
tls_cert)
|
||||
if not socket_path:
|
||||
socket_path = '%s/%s.sock' % (self.base_amp_path, listener.id)
|
||||
return self._get_template().render(
|
||||
{'loadbalancer': loadbalancer,
|
||||
'user_group': user_group,
|
||||
'stats_sock': socket_path},
|
||||
constants=constants)
|
||||
|
||||
def _transform_loadbalancer(self, loadbalancer, listener, tls_cert):
|
||||
"""Transforms a load balanacer into an object that will
|
||||
|
||||
be processed by the templating system
|
||||
"""
|
||||
listener = self._transform_listener(listener, tls_cert)
|
||||
return {
|
||||
'name': loadbalancer.name,
|
||||
'vip_address': loadbalancer.vip.ip_address,
|
||||
'listener': listener
|
||||
}
|
||||
|
||||
def _transform_listener(self, listener, tls_cert):
|
||||
"""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],
|
||||
'protocol': listener.protocol
|
||||
}
|
||||
if listener.connection_limit and listener.connection_limit > -1:
|
||||
ret_value['connection_limit'] = listener.connection_limit
|
||||
if listener.tls_container_id:
|
||||
ret_value['default_tls_path'] = '%s/%s/%s.pem' % (
|
||||
self.cert_store_path, listener.id, tls_cert.primary_cn)
|
||||
if listener.sni_containers:
|
||||
ret_value['crt_dir'] = '%s/%s' % (
|
||||
self.cert_store_path, listener.id)
|
||||
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,
|
||||
'operating_status': pool.operating_status
|
||||
}
|
||||
members = [self._transform_member(x)
|
||||
for x in pool.members if self._include_member(x)]
|
||||
ret_value['members'] = members
|
||||
if pool.healthmonitor:
|
||||
ret_value['health_monitor'] = self._transform_health_monitor(
|
||||
pool.healthmonitor)
|
||||
if pool.sessionpersistence:
|
||||
ret_value[
|
||||
'session_persistence'] = self._transform_session_persistence(
|
||||
pool.sessionpersistence)
|
||||
return ret_value
|
||||
|
||||
def _transform_session_persistence(self, persistence):
|
||||
"""Transforms session persistence into an object that will
|
||||
|
||||
be processed by the templating system
|
||||
"""
|
||||
return {
|
||||
'type': persistence.type,
|
||||
'cookie_name': persistence.cookie_name
|
||||
}
|
||||
|
||||
def _transform_member(self, 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,
|
||||
'subnet_id': member.subnet_id,
|
||||
'operating_status': member.operating_status
|
||||
}
|
||||
|
||||
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,
|
||||
'fall_threshold': monitor.fall_threshold,
|
||||
'http_method': monitor.http_method,
|
||||
'url_path': monitor.url_path,
|
||||
'expected_codes': '|'.join(
|
||||
self._expand_expected_codes(monitor.expected_codes)),
|
||||
'enabled': monitor.enabled,
|
||||
}
|
||||
|
||||
def _include_member(self, member):
|
||||
"""Members that should be included
|
||||
|
||||
Return only those that meet the criteria for templating
|
||||
"""
|
||||
return (
|
||||
member.operating_status in
|
||||
ACTIVE_PENDING_STATUSES and
|
||||
member.enabled
|
||||
)
|
||||
|
||||
def _expand_expected_codes(self, codes):
|
||||
"""Expand the expected code string in set of codes.
|
||||
|
||||
200-204 -> 200, 201, 202, 204
|
||||
200, 203 -> 200, 203
|
||||
"""
|
||||
|
||||
retval = set()
|
||||
for code in codes.replace(',', ' ').split(' '):
|
||||
code = code.strip()
|
||||
|
||||
if not code:
|
||||
continue
|
||||
elif '-' in code:
|
||||
low, hi = code.split('-')[:2]
|
||||
retval.update(
|
||||
str(i) for i in six.moves.xrange(int(low), int(hi) + 1))
|
||||
else:
|
||||
retval.add(code)
|
||||
return retval
|
@ -0,0 +1,33 @@
|
||||
{# # Copyright (c) 2015 Rackspace
|
||||
#
|
||||
# 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 {{ loadbalancer_name }}
|
||||
global
|
||||
daemon
|
||||
user nobody
|
||||
group {{ usergroup }}
|
||||
log /dev/log local0
|
||||
log /dev/log local1 notice
|
||||
stats socket {{ sock_path }} mode 0666 level user
|
||||
|
||||
defaults
|
||||
log global
|
||||
retries 3
|
||||
option redispatch
|
||||
timeout connect 5000
|
||||
timeout client 50000
|
||||
timeout server 50000
|
||||
|
||||
{% block proxies %}{% endblock proxies %}
|
@ -0,0 +1,27 @@
|
||||
{# # Copyright (c) 2015 Rackspace
|
||||
#
|
||||
# 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 'haproxy_proxies.template' %}
|
||||
{% set loadbalancer_name = loadbalancer.name %}
|
||||
{% set usergroup = user_group %}
|
||||
{% set sock_path = stats_sock %}
|
||||
|
||||
{% block proxies %}
|
||||
{% from 'haproxy_proxies.template' import frontend_macro as frontend_macro, backend_macro%}
|
||||
{{ frontend_macro(constants, loadbalancer.listener, loadbalancer.vip_address) }}
|
||||
{% if loadbalancer.listener.default_pool %}
|
||||
{{ backend_macro(constants, loadbalancer.listener, loadbalancer.listener.default_pool) }}
|
||||
{% endif %}
|
||||
{% endblock proxies %}
|
@ -0,0 +1,29 @@
|
||||
{# # Copyright (c) 2015 Rackspace
|
||||
#
|
||||
# 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 'haproxy_proxies.template' %}
|
||||
{% set loadbalancer_name = loadbalancer.name %}
|
||||
{% set usergroup = user_group %}
|
||||
{% set sock_path = stats_sock %}
|
||||
|
||||
{% block proxies %}
|
||||
{% from 'haproxy_proxies.template' import frontend_macro as frontend_macro, backend_macro%}
|
||||
{% for listener in loadbalancer.listeners %}
|
||||
{{ frontend_macro(constants, listener, loadbalancer.vip_address) }}
|
||||
{% if listener.default_pool %}
|
||||
{{ backend_macro(constants, listener, listener.default_pool) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endblock proxies %}
|
@ -0,0 +1,95 @@
|
||||
{# # Copyright (c) 2015 Rackspace
|
||||
#
|
||||
# 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 'haproxy_base.template' %}
|
||||
|
||||
{% macro bind_macro(constants, listener, lb_vip_address) %}
|
||||
{% if listener.default_tls_path %}
|
||||
{% set def_crt_opt = "ssl crt %s"|format(listener.default_tls_path)|trim() %}
|
||||
{% else %}
|
||||
{% set def_crt_opt = "" %}
|
||||
{% endif %}
|
||||
{% if listener.crt_dir %}
|
||||
{% set crt_dir_opt = "crt %s"|format(listener.crt_dir)|trim() %}
|
||||
{% else %}
|
||||
{% set crt_dir_opt = "" %}
|
||||
{% endif %}
|
||||
bind {{ lb_vip_address }}:{{ listener.protocol_port }} {{ "%s %s"|format(def_crt_opt, crt_dir_opt)|trim() }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro use_backend_macro(listener) %}
|
||||
{% if listener.default_pool %}
|
||||
default_backend {{ listener.default_pool.id }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro frontend_macro(constants, listener, lb_vip_address) %}
|
||||
frontend {{ listener.id }}
|
||||
option tcplog
|
||||
{% if listener.connection_limit is defined %}
|
||||
maxconn {{ listener.connection_limit }}
|
||||
{% endif %}
|
||||
{% if listener.protocol_mode == constants.PROTOCOL_HTTP.lower() %}
|
||||
option forwardfor
|
||||
{% endif %}
|
||||
{{ bind_macro(constants, listener, lb_vip_address)|trim() }}
|
||||
mode {{ listener.protocol_mode }}
|
||||
{% if listener.default_pool %}
|
||||
default_backend {{ listener.default_pool.id }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro backend_macro(constants, listener, pool) %}
|
||||
backend {{ pool.id }}
|
||||
mode {{ pool.protocol }}
|
||||
balance {{ pool.lb_algorithm }}
|
||||
{% if listener.protocol == constants.PROTOCOL_TERMINATED_HTTPS %}
|
||||
redirect scheme https if !{ ssl_fc }
|
||||
{% endif %}
|
||||
{% if pool.session_persistence %}
|
||||
{% if pool.session_persistence.type == constants.SESSION_PERSISTENCE_SOURCE_IP %}
|
||||
stick-table type ip size 10k
|
||||
stick on src
|
||||
{% elif pool.session_persistence.type == constants.SESSION_PERSISTENCE_HTTP_COOKIE %}
|
||||
cookie SRV insert indirect nocache
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if pool.health_monitor %}
|
||||
timeout check {{ pool.health_monitor.timeout }}
|
||||
{% if pool.health_monitor.type == constants.HEALTH_MONITOR_HTTP or pool.health_monitor.type == constants.HEALTH_MONITOR_HTTPS %}
|
||||
option httpchk {{ pool.health_monitor.http_method }} {{ pool.health_monitor.url_path }}
|
||||
http-check expect rstatus {{ pool.health_monitor.expected_codes }}
|
||||
{% endif %}
|
||||
{% if pool.health_monitor.type == constants.HEALTH_MONITOR_HTTPS %}
|
||||
option ssl-hello-chk
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if listener.protocol_mode == constants.PROTOCOL_HTTP.lower() %}
|
||||
option forwardfor
|
||||
{% endif %}
|
||||
{% for member in pool.members %}
|
||||
{% if pool.health_monitor %}
|
||||
{% set hm_opt = " check inter %ds fall %d"|format(pool.health_monitor.delay, pool.health_monitor.fall_threshold) %}
|
||||
{% else %}
|
||||
{% set hm_opt = "" %}
|
||||
{% endif %}
|
||||
{%if pool.session_persistence.type == constants.SESSION_PERSISTENCE_HTTP_COOKIE %}
|
||||
{% set persistence_opt = " cookie %s"|format(member.id) %}
|
||||
{% else %}
|
||||
{% set persistence_opt = "" %}
|
||||
{% endif %}
|
||||
{{ "server %s %s:%d weight %s%s%s"|e|format(member.id, member.address, member.protocol_port, member.weight, hm_opt, persistence_opt)|trim() }}
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
@ -34,6 +34,7 @@ SUPPORTED_HEALTH_MONITOR_TYPES = (HEALTH_MONITOR_HTTP, HEALTH_MONITOR_HTTPS,
|
||||
PROTOCOL_TCP = 'TCP'
|
||||
PROTOCOL_HTTP = 'HTTP'
|
||||
PROTOCOL_HTTPS = 'HTTPS'
|
||||
PROTOCOL_TERMINATED_HTTPS = 'TERMINATED_HTTPS'
|
||||
SUPPORTED_PROTOCOLS = (PROTOCOL_TCP, PROTOCOL_HTTPS, PROTOCOL_HTTP)
|
||||
|
||||
ACTIVE = 'ACTIVE'
|
||||
|
@ -190,6 +190,18 @@ class SNI(BaseDataModel):
|
||||
self.tls_container_id = tls_container_id
|
||||
|
||||
|
||||
class TLSContainer(BaseDataModel):
|
||||
|
||||
def __init__(self, id=None, primary_cn=None, certificate=None,
|
||||
private_key=None, passphrase=None, intermediates=[]):
|
||||
self.id = id
|
||||
self.primary_cn = primary_cn
|
||||
self.certificate = certificate
|
||||
self.private_key = private_key
|
||||
self.passphrase = passphrase
|
||||
self.intermediates = intermediates
|
||||
|
||||
|
||||
class Amphora(BaseDataModel):
|
||||
|
||||
def __init__(self, id=None, load_balancer_id=None, compute_id=None,
|
||||
|
@ -0,0 +1,312 @@
|
||||
# Copyright 2014 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.amphorae.drivers.haproxy.jinja import jinja_cfg
|
||||
from octavia.tests.unit import base as base
|
||||
from octavia.tests.unit.common.sample_configs import sample_configs
|
||||
|
||||
|
||||
class TestHaproxyCfg(base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestHaproxyCfg, self).setUp()
|
||||
self.jinja_cfg = jinja_cfg.JinjaTemplater(
|
||||
base_amp_path='/var/lib/octavia',
|
||||
base_crt_dir='/listeners')
|
||||
|
||||
def test_get_template(self):
|
||||
template = self.jinja_cfg._get_template()
|
||||
self.assertEqual('haproxy_listener.template', template.name)
|
||||
|
||||
def test_render_template_tls(self):
|
||||
fe = ("frontend sample_listener_id_1\n"
|
||||
" option tcplog\n"
|
||||
" maxconn 98\n"
|
||||
" option forwardfor\n"
|
||||
" bind 10.0.0.2:443 "
|
||||
"ssl crt /var/lib/octavia/listeners/"
|
||||
"sample_listener_id_1/FakeCN.pem "
|
||||
"crt /var/lib/octavia/listeners/sample_listener_id_1\n"
|
||||
" mode http\n"
|
||||
" default_backend sample_pool_id_1\n\n")
|
||||
be = ("backend sample_pool_id_1\n"
|
||||
" mode http\n"
|
||||
" balance roundrobin\n"
|
||||
" redirect scheme https if !{ ssl_fc }\n"
|
||||
" cookie SRV insert indirect nocache\n"
|
||||
" timeout check 31\n"
|
||||
" option httpchk GET /index.html\n"
|
||||
" http-check expect rstatus 418\n"
|
||||
" option forwardfor\n"
|
||||
" server sample_member_id_1 10.0.0.99:82 "
|
||||
"weight 13 check inter 30s fall 3 cookie sample_member_id_1\n"
|
||||
" server sample_member_id_2 10.0.0.98:82 "
|
||||
"weight 13 check inter 30s fall 3 cookie sample_member_id_2\n\n")
|
||||
tls_tupe = sample_configs.sample_tls_container_tuple(
|
||||
certificate='imaCert1', private_key='imaPrivateKey1',
|
||||
primary_cn='FakeCN')
|
||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||
sample_configs.sample_listener_tuple(proto='TERMINATED_HTTPS',
|
||||
tls=True, sni=True),
|
||||
tls_tupe)
|
||||
self.assertEqual(
|
||||
sample_configs.sample_base_expected_config(
|
||||
frontend=fe, backend=be),
|
||||
rendered_obj)
|
||||
|
||||
def test_render_template_tls_no_sni(self):
|
||||
fe = ("frontend sample_listener_id_1\n"
|
||||
" option tcplog\n"
|
||||
" maxconn 98\n"
|
||||
" option forwardfor\n"
|
||||
" bind 10.0.0.2:443 "
|
||||
"ssl crt /var/lib/octavia/listeners/"
|
||||
"sample_listener_id_1/FakeCN.pem\n"
|
||||
" mode http\n"
|
||||
" default_backend sample_pool_id_1\n\n")
|
||||
be = ("backend sample_pool_id_1\n"
|
||||
" mode http\n"
|
||||
" balance roundrobin\n"
|
||||
" redirect scheme https if !{ ssl_fc }\n"
|
||||
" cookie SRV insert indirect nocache\n"
|
||||
" timeout check 31\n"
|
||||
" option httpchk GET /index.html\n"
|
||||
" http-check expect rstatus 418\n"
|
||||
" option forwardfor\n"
|
||||
" server sample_member_id_1 10.0.0.99:82 "
|
||||
"weight 13 check inter 30s fall 3 cookie sample_member_id_1\n"
|
||||
" server sample_member_id_2 10.0.0.98:82 "
|
||||
"weight 13 check inter 30s fall 3 cookie sample_member_id_2\n\n")
|
||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||
sample_configs.sample_listener_tuple(
|
||||
proto='TERMINATED_HTTPS', tls=True),
|
||||
tls_cert=sample_configs.sample_tls_container_tuple(
|
||||
certificate='ImAalsdkfjCert',
|
||||
private_key='ImAsdlfksdjPrivateKey',
|
||||
primary_cn="FakeCN"))
|
||||
self.assertEqual(
|
||||
sample_configs.sample_base_expected_config(
|
||||
frontend=fe, backend=be),
|
||||
rendered_obj)
|
||||
|
||||
def test_render_template_http(self):
|
||||
be = ("backend sample_pool_id_1\n"
|
||||
" mode http\n"
|
||||
" balance roundrobin\n"
|
||||
" cookie SRV insert indirect nocache\n"
|
||||
" timeout check 31\n"
|
||||
" option httpchk GET /index.html\n"
|
||||
" http-check expect rstatus 418\n"
|
||||
" option forwardfor\n"
|
||||
" server sample_member_id_1 10.0.0.99:82 "
|
||||
"weight 13 check inter 30s fall 3 cookie sample_member_id_1\n"
|
||||
" server sample_member_id_2 10.0.0.98:82 "
|
||||
"weight 13 check inter 30s fall 3 cookie sample_member_id_2\n\n")
|
||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||
sample_configs.sample_listener_tuple())
|
||||
self.assertEqual(
|
||||
sample_configs.sample_base_expected_config(backend=be),
|
||||
rendered_obj)
|
||||
|
||||
def test_render_template_https(self):
|
||||
fe = ("frontend sample_listener_id_1\n"
|
||||
" option tcplog\n"
|
||||
" maxconn 98\n"
|
||||
" bind 10.0.0.2:443\n"
|
||||
" mode tcp\n"
|
||||
" default_backend sample_pool_id_1\n\n")
|
||||
be = ("backend sample_pool_id_1\n"
|
||||
" mode tcp\n"
|
||||
" balance roundrobin\n"
|
||||
" cookie SRV insert indirect nocache\n"
|
||||
" timeout check 31\n"
|
||||
" option httpchk GET /index.html\n"
|
||||
" http-check expect rstatus 418\n"
|
||||
" option ssl-hello-chk\n"
|
||||
" server sample_member_id_1 10.0.0.99:82 "
|
||||
"weight 13 check inter 30s fall 3 cookie sample_member_id_1\n"
|
||||
" server sample_member_id_2 10.0.0.98:82 "
|
||||
"weight 13 check inter 30s fall 3 cookie sample_member_id_2\n\n")
|
||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||
sample_configs.sample_listener_tuple(proto='HTTPS'))
|
||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
||||
frontend=fe, backend=be), rendered_obj)
|
||||
|
||||
def test_render_template_no_monitor_http(self):
|
||||
be = ("backend sample_pool_id_1\n"
|
||||
" mode http\n"
|
||||
" balance roundrobin\n"
|
||||
" cookie SRV insert indirect nocache\n"
|
||||
" option forwardfor\n"
|
||||
" server sample_member_id_1 10.0.0.99:82 weight 13 "
|
||||
"cookie sample_member_id_1\n"
|
||||
" server sample_member_id_2 10.0.0.98:82 weight 13 "
|
||||
"cookie sample_member_id_2\n\n")
|
||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||
sample_configs.sample_listener_tuple(proto='HTTP', monitor=False))
|
||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
||||
backend=be), rendered_obj)
|
||||
|
||||
def test_render_template_no_monitor_https(self):
|
||||
fe = ("frontend sample_listener_id_1\n"
|
||||
" option tcplog\n"
|
||||
" maxconn 98\n"
|
||||
" bind 10.0.0.2:443\n"
|
||||
" mode tcp\n"
|
||||
" default_backend sample_pool_id_1\n\n")
|
||||
be = ("backend sample_pool_id_1\n"
|
||||
" mode tcp\n"
|
||||
" balance roundrobin\n"
|
||||
" cookie SRV insert indirect nocache\n"
|
||||
" server sample_member_id_1 10.0.0.99:82 weight 13 "
|
||||
"cookie sample_member_id_1\n"
|
||||
" server sample_member_id_2 10.0.0.98:82 weight 13 "
|
||||
"cookie sample_member_id_2\n\n")
|
||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||
sample_configs.sample_listener_tuple(proto='HTTPS', monitor=False))
|
||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
||||
frontend=fe, backend=be), rendered_obj)
|
||||
|
||||
def test_render_template_no_persistence_https(self):
|
||||
fe = ("frontend sample_listener_id_1\n"
|
||||
" option tcplog\n"
|
||||
" maxconn 98\n"
|
||||
" bind 10.0.0.2:443\n"
|
||||
" mode tcp\n"
|
||||
" default_backend sample_pool_id_1\n\n")
|
||||
be = ("backend sample_pool_id_1\n"
|
||||
" mode tcp\n"
|
||||
" balance roundrobin\n"
|
||||
" server sample_member_id_1 10.0.0.99:82 weight 13\n"
|
||||
" server sample_member_id_2 10.0.0.98:82 weight 13\n\n")
|
||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||
sample_configs.sample_listener_tuple(proto='HTTPS', monitor=False,
|
||||
persistence=False))
|
||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
||||
frontend=fe, backend=be), rendered_obj)
|
||||
|
||||
def test_render_template_no_persistence_http(self):
|
||||
be = ("backend sample_pool_id_1\n"
|
||||
" mode http\n"
|
||||
" balance roundrobin\n"
|
||||
" option forwardfor\n"
|
||||
" server sample_member_id_1 10.0.0.99:82 weight 13\n"
|
||||
" server sample_member_id_2 10.0.0.98:82 weight 13\n\n")
|
||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||
sample_configs.sample_listener_tuple(proto='HTTP', monitor=False,
|
||||
persistence=False))
|
||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
||||
backend=be), rendered_obj)
|
||||
|
||||
def test_render_template_sourceip_persistence(self):
|
||||
be = ("backend sample_pool_id_1\n"
|
||||
" mode http\n"
|
||||
" balance roundrobin\n"
|
||||
" stick-table type ip size 10k\n"
|
||||
" stick on src\n"
|
||||
" timeout check 31\n"
|
||||
" option httpchk GET /index.html\n"
|
||||
" http-check expect rstatus 418\n"
|
||||
" option forwardfor\n"
|
||||
" server sample_member_id_1 10.0.0.99:82 "
|
||||
"weight 13 check inter 30s fall 3\n"
|
||||
" server sample_member_id_2 10.0.0.98:82 "
|
||||
"weight 13 check inter 30s fall 3\n\n")
|
||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||
sample_configs.sample_listener_tuple(
|
||||
persistence_type='SOURCE_IP'))
|
||||
self.assertEqual(
|
||||
sample_configs.sample_base_expected_config(backend=be),
|
||||
rendered_obj)
|
||||
|
||||
def test_transform_session_persistence(self):
|
||||
in_persistence = sample_configs.sample_session_persistence_tuple()
|
||||
ret = self.jinja_cfg._transform_session_persistence(in_persistence)
|
||||
self.assertEqual(sample_configs.RET_PERSISTENCE, ret)
|
||||
|
||||
def test_transform_health_monitor(self):
|
||||
in_persistence = sample_configs.sample_health_monitor_tuple()
|
||||
ret = self.jinja_cfg._transform_health_monitor(in_persistence)
|
||||
self.assertEqual(sample_configs.RET_MONITOR, ret)
|
||||
|
||||
def test_transform_member(self):
|
||||
in_member = sample_configs.sample_member_tuple('sample_member_id_1',
|
||||
'10.0.0.99')
|
||||
ret = self.jinja_cfg._transform_member(in_member)
|
||||
self.assertEqual(sample_configs.RET_MEMBER_1, ret)
|
||||
|
||||
def test_transform_pool(self):
|
||||
in_pool = sample_configs.sample_pool_tuple()
|
||||
ret = self.jinja_cfg._transform_pool(in_pool)
|
||||
self.assertEqual(sample_configs.RET_POOL, ret)
|
||||
|
||||
def test_transform_listener(self):
|
||||
in_listener = sample_configs.sample_listener_tuple()
|
||||
ret = self.jinja_cfg._transform_listener(in_listener, None)
|
||||
self.assertEqual(sample_configs.RET_LISTENER, ret)
|
||||
|
||||
def test_transform_loadbalancer(self):
|
||||
in_listener = sample_configs.sample_listener_tuple()
|
||||
ret = self.jinja_cfg._transform_loadbalancer(
|
||||
in_listener.loadbalancer, in_listener, None)
|
||||
self.assertEqual(sample_configs.RET_LB, ret)
|
||||
|
||||
def test_include_member(self):
|
||||
ret = self.jinja_cfg._include_member(
|
||||
sample_configs.sample_member_tuple('sample_member_id_1',
|
||||
'10.0.0.99'))
|
||||
self.assertTrue(ret)
|
||||
|
||||
def test_include_member_invalid_status(self):
|
||||
ret = self.jinja_cfg._include_member(
|
||||
sample_configs.sample_member_tuple('sample_member_id_1',
|
||||
'10.0.0.99',
|
||||
operating_status='PENDING'))
|
||||
self.assertFalse(ret)
|
||||
|
||||
def test_include_member_invalid_admin_state(self):
|
||||
ret = self.jinja_cfg._include_member(
|
||||
sample_configs.sample_member_tuple('sample_member_id_1',
|
||||
'10.0.0.99',
|
||||
enabled=False))
|
||||
self.assertFalse(ret)
|
||||
|
||||
def test_expand_expected_codes(self):
|
||||
exp_codes = ''
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
set([]))
|
||||
exp_codes = '200'
|
||||
self.assertEqual(
|
||||
self.jinja_cfg._expand_expected_codes(exp_codes), set(['200']))
|
||||
exp_codes = '200, 201'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
set(['200', '201']))
|
||||
exp_codes = '200, 201,202'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
set(['200', '201', '202']))
|
||||
exp_codes = '200-202'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
set(['200', '201', '202']))
|
||||
exp_codes = '200-202, 205'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
set(['200', '201', '202', '205']))
|
||||
exp_codes = '200, 201-203'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
set(['200', '201', '202', '203']))
|
||||
exp_codes = '200, 201-203, 205'
|
||||
self.assertEqual(self.jinja_cfg._expand_expected_codes(exp_codes),
|
||||
set(['200', '201', '202', '203', '205']))
|
||||
exp_codes = '201-200, 205'
|
||||
self.assertEqual(
|
||||
self.jinja_cfg._expand_expected_codes(exp_codes), set(['205']))
|
308
octavia/tests/unit/common/sample_configs/sample_configs.py
Normal file
308
octavia/tests/unit/common/sample_configs/sample_configs.py
Normal file
@ -0,0 +1,308 @@
|
||||
# Copyright 2014 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 collections
|
||||
|
||||
RET_PERSISTENCE = {
|
||||
'type': 'HTTP_COOKIE',
|
||||
'cookie_name': 'HTTP_COOKIE'}
|
||||
|
||||
RET_MONITOR = {
|
||||
'id': 'sample_monitor_id_1',
|
||||
'type': 'HTTP',
|
||||
'delay': 30,
|
||||
'timeout': 31,
|
||||
'fall_threshold': 3,
|
||||
'http_method': 'GET',
|
||||
'url_path': '/index.html',
|
||||
'expected_codes': '418',
|
||||
'enabled': True}
|
||||
|
||||
RET_MEMBER_1 = {
|
||||
'id': 'sample_member_id_1',
|
||||
'address': '10.0.0.99',
|
||||
'protocol_port': 82,
|
||||
'weight': 13,
|
||||
'subnet_id': '10.0.0.1/24',
|
||||
'enabled': True,
|
||||
'operating_status': 'ACTIVE'}
|
||||
|
||||
RET_MEMBER_2 = {
|
||||
'id': 'sample_member_id_2',
|
||||
'address': '10.0.0.98',
|
||||
'protocol_port': 82,
|
||||
'weight': 13,
|
||||
'subnet_id': '10.0.0.1/24',
|
||||
'enabled': True,
|
||||
'operating_status': 'ACTIVE'}
|
||||
|
||||
RET_POOL = {
|
||||
'id': 'sample_pool_id_1',
|
||||
'protocol': 'http',
|
||||
'lb_algorithm': 'roundrobin',
|
||||
'members': [RET_MEMBER_1, RET_MEMBER_2],
|
||||
'health_monitor': RET_MONITOR,
|
||||
'session_persistence': RET_PERSISTENCE,
|
||||
'enabled': True,
|
||||
'operating_status': 'ACTIVE'}
|
||||
|
||||
RET_DEF_TLS_CONT = {'id': 'cont_id_1', 'allencompassingpem': 'imapem',
|
||||
'primary_cn': 'FakeCn'}
|
||||
RET_SNI_CONT_1 = {'id': 'cont_id_2', 'allencompassingpem': 'imapem2',
|
||||
'primary_cn': 'FakeCn'}
|
||||
RET_SNI_CONT_2 = {'id': 'cont_id_3', 'allencompassingpem': 'imapem3',
|
||||
'primary_cn': 'FakeCn2'}
|
||||
|
||||
RET_LISTENER = {
|
||||
'id': 'sample_listener_id_1',
|
||||
'protocol_port': '80',
|
||||
'protocol': 'HTTP',
|
||||
'protocol_mode': 'http',
|
||||
'default_pool': RET_POOL,
|
||||
'connection_limit': 98}
|
||||
|
||||
RET_LISTENER_TLS = {
|
||||
'id': 'sample_listener_id_1',
|
||||
'protocol_port': '443',
|
||||
'protocol': 'TERMINATED_HTTPS',
|
||||
'protocol_mode': 'http',
|
||||
'default_pool': RET_POOL,
|
||||
'connection_limit': 98,
|
||||
'tls_container_id': 'cont_id_1',
|
||||
'default_tls_path': '/etc/ssl/sample_loadbalancer_id_1/fakeCN.pem',
|
||||
'default_tls_container': RET_DEF_TLS_CONT}
|
||||
|
||||
RET_LISTENER_TLS_SNI = {
|
||||
'id': 'sample_listener_id_1',
|
||||
'protocol_port': '443',
|
||||
'protocol': 'http',
|
||||
'protocol': 'TERMINATED_HTTPS',
|
||||
'default_pool': RET_POOL,
|
||||
'connection_limit': 98,
|
||||
'tls_container_id': 'cont_id_1',
|
||||
'default_tls_path': '/etc/ssl/sample_loadbalancer_id_1/fakeCN.pem',
|
||||
'default_tls_container': RET_DEF_TLS_CONT,
|
||||
'crt_dir': '/v2/sample_loadbalancer_id_1',
|
||||
'sni_container_ids': ['cont_id_2', 'cont_id_3'],
|
||||
'sni_containers': [RET_SNI_CONT_1, RET_SNI_CONT_2]}
|
||||
|
||||
RET_LB = {
|
||||
'name': 'test-lb',
|
||||
'vip_address': '10.0.0.2',
|
||||
'listener': RET_LISTENER}
|
||||
|
||||
RET_LB_TLS = {
|
||||
'name': 'test-lb',
|
||||
'vip_address': '10.0.0.2',
|
||||
'listener': RET_LISTENER_TLS}
|
||||
|
||||
RET_LB_TLS_SNI = {
|
||||
'name': 'test-lb',
|
||||
'vip_address': '10.0.0.2',
|
||||
'listener': RET_LISTENER_TLS_SNI}
|
||||
|
||||
|
||||
def sample_loadbalancer_tuple(proto=None, monitor=True, persistence=True,
|
||||
persistence_type=None, tls=False, sni=False):
|
||||
proto = 'HTTP' if proto is None else proto
|
||||
in_lb = collections.namedtuple(
|
||||
'loadbalancer', 'id, name, protocol, vip, '
|
||||
'listeners')
|
||||
return in_lb(
|
||||
id='sample_loadbalancer_id_1',
|
||||
name='test-lb',
|
||||
protocol=proto,
|
||||
vip=sample_vip_tuple(),
|
||||
listeners=[sample_listener_tuple(proto=proto, monitor=monitor,
|
||||
persistence=persistence,
|
||||
persistence_type=persistence_type,
|
||||
tls=tls,
|
||||
sni=sni)]
|
||||
)
|
||||
|
||||
|
||||
def sample_listener_loadbalancer_tuple(proto=None):
|
||||
proto = 'HTTP' if proto is None else proto
|
||||
in_lb = collections.namedtuple(
|
||||
'loadbalancer', 'id, name, protocol, vip')
|
||||
return in_lb(
|
||||
id='sample_loadbalancer_id_1',
|
||||
name='test-lb',
|
||||
protocol=proto,
|
||||
vip=sample_vip_tuple()
|
||||
)
|
||||
|
||||
|
||||
def sample_vip_tuple():
|
||||
vip = collections.namedtuple('vip', 'ip_address')
|
||||
return vip(ip_address='10.0.0.2')
|
||||
|
||||
|
||||
def sample_listener_tuple(proto=None, monitor=True, persistence=True,
|
||||
persistence_type=None, tls=False, sni=False):
|
||||
proto = 'HTTP' if proto is None else proto
|
||||
port = '443' if proto is 'HTTPS' or proto is 'TERMINATED_HTTPS' else '80'
|
||||
in_listener = collections.namedtuple(
|
||||
'listener', 'id, protocol_port, protocol, default_pool, '
|
||||
'connection_limit, tls_container_id, '
|
||||
'sni_container_ids, default_tls_container, '
|
||||
'sni_containers, loadbalancer')
|
||||
return in_listener(
|
||||
id='sample_listener_id_1',
|
||||
protocol_port=port,
|
||||
protocol=proto,
|
||||
loadbalancer=sample_listener_loadbalancer_tuple(proto=proto),
|
||||
default_pool=sample_pool_tuple(
|
||||
proto=proto, monitor=monitor, persistence=persistence,
|
||||
persistence_type=persistence_type),
|
||||
connection_limit=98,
|
||||
tls_container_id='cont_id_1' if tls else '',
|
||||
sni_container_ids=['cont_id_2', 'cont_id_3'] if sni else [],
|
||||
default_tls_container=sample_tls_container_tuple(
|
||||
id='cont_id_1', certificate='--imapem1--\n',
|
||||
private_key='--imakey1--\n', intermediates=[
|
||||
'--imainter1--\n', '--imainter1too--\n'],
|
||||
primary_cn='aFakeCN'
|
||||
) if tls else '',
|
||||
sni_containers=[
|
||||
sample_tls_sni_container_tuple(
|
||||
tls_container=sample_tls_container_tuple(
|
||||
id='cont_id_2', certificate='--imapem2--\n',
|
||||
private_key='--imakey2--\n', intermediates=[
|
||||
'--imainter2--\n', '--imainter2too--\n'
|
||||
], primary_cn='aFakeCN')),
|
||||
sample_tls_sni_container_tuple(
|
||||
tls_container=sample_tls_container_tuple(
|
||||
id='cont_id_3', certificate='--imapem3--\n',
|
||||
private_key='--imakey3--\n', intermediates=[
|
||||
'--imainter3--\n', '--imainter3too--\n'
|
||||
], primary_cn='aFakeCN'))]
|
||||
if sni else []
|
||||
)
|
||||
|
||||
|
||||
def sample_tls_sni_container_tuple(tls_container=None):
|
||||
sc = collections.namedtuple('sni_container', 'tls_container')
|
||||
return sc(tls_container=tls_container)
|
||||
|
||||
|
||||
def sample_tls_sni_containers_tuple(tls_container=None):
|
||||
sc = collections.namedtuple('sni_containers', 'tls_container')
|
||||
return [sc(tls_container=tls_container)]
|
||||
|
||||
|
||||
def sample_tls_container_tuple(id='cont_id_1', certificate=None,
|
||||
private_key=None, intermediates=[],
|
||||
primary_cn=None):
|
||||
sc = collections.namedtuple(
|
||||
'tls_container',
|
||||
'id, certificate, private_key, intermediates, primary_cn')
|
||||
return sc(id=id, certificate=certificate, private_key=private_key,
|
||||
intermediates=intermediates, primary_cn=primary_cn)
|
||||
|
||||
|
||||
def sample_pool_tuple(proto=None, monitor=True, persistence=True,
|
||||
persistence_type=None):
|
||||
proto = 'HTTP' if proto is None else proto
|
||||
in_pool = collections.namedtuple(
|
||||
'pool', 'id, protocol, lb_algorithm, members, healthmonitor,'
|
||||
'sessionpersistence, enabled, operating_status')
|
||||
mon = sample_health_monitor_tuple(proto=proto) if monitor is True else None
|
||||
persis = sample_session_persistence_tuple(
|
||||
persistence_type=persistence_type) if persistence is True else None
|
||||
return in_pool(
|
||||
id='sample_pool_id_1',
|
||||
protocol=proto,
|
||||
lb_algorithm='ROUND_ROBIN',
|
||||
members=[sample_member_tuple('sample_member_id_1', '10.0.0.99'),
|
||||
sample_member_tuple('sample_member_id_2', '10.0.0.98')],
|
||||
healthmonitor=mon,
|
||||
sessionpersistence=persis,
|
||||
enabled=True,
|
||||
operating_status='ACTIVE')
|
||||
|
||||
|
||||
def sample_member_tuple(id, ip, enabled=True, operating_status='ACTIVE'):
|
||||
in_member = collections.namedtuple('member',
|
||||
'id, ip_address, protocol_port, '
|
||||
'weight, subnet_id, '
|
||||
'enabled, operating_status')
|
||||
return in_member(
|
||||
id=id,
|
||||
ip_address=ip,
|
||||
protocol_port=82,
|
||||
weight=13,
|
||||
subnet_id='10.0.0.1/24',
|
||||
enabled=enabled,
|
||||
operating_status=operating_status)
|
||||
|
||||
|
||||
def sample_session_persistence_tuple(persistence_type=None):
|
||||
spersistence = collections.namedtuple('SessionPersistence',
|
||||
'type, cookie_name')
|
||||
pt = 'HTTP_COOKIE' if persistence_type is None else persistence_type
|
||||
return spersistence(type=pt,
|
||||
cookie_name=pt)
|
||||
|
||||
|
||||
def sample_health_monitor_tuple(proto='HTTP'):
|
||||
proto = 'HTTP' if proto is 'TERMINATED_HTTPS' else proto
|
||||
monitor = collections.namedtuple(
|
||||
'monitor', 'id, type, delay, timeout, fall_threshold, http_method, '
|
||||
'url_path, expected_codes, enabled')
|
||||
|
||||
return monitor(id='sample_monitor_id_1', type=proto, delay=30,
|
||||
timeout=31, fall_threshold=3, http_method='GET',
|
||||
url_path='/index.html', expected_codes='418',
|
||||
enabled=True)
|
||||
|
||||
|
||||
def sample_base_expected_config(frontend=None, backend=None):
|
||||
if frontend is None:
|
||||
frontend = ("frontend sample_listener_id_1\n"
|
||||
" option tcplog\n"
|
||||
" maxconn 98\n"
|
||||
" option forwardfor\n"
|
||||
" bind 10.0.0.2:80\n"
|
||||
" mode http\n"
|
||||
" default_backend sample_pool_id_1\n\n")
|
||||
if backend is None:
|
||||
backend = ("backend sample_pool_id_1\n"
|
||||
" mode http\n"
|
||||
" balance roundrobin\n"
|
||||
" cookie SRV insert indirect nocache\n"
|
||||
" timeout check 31\n"
|
||||
" option httpchk GET /index.html\n"
|
||||
" http-check expect rstatus 418\n"
|
||||
" server sample_member_id_1 10.0.0.99:82 weight 13 "
|
||||
"check inter 30s fall 3 cookie sample_member_id_1\n"
|
||||
" server sample_member_id_2 10.0.0.98:82 weight 13 "
|
||||
"check inter 30s fall 3 cookie sample_member_id_2\n")
|
||||
return ("# Configuration for test-lb\n"
|
||||
"global\n"
|
||||
" daemon\n"
|
||||
" user nobody\n"
|
||||
" group nogroup\n"
|
||||
" log /dev/log local0\n"
|
||||
" log /dev/log local1 notice\n"
|
||||
" stats socket /var/lib/octavia/sample_listener_id_1.sock"
|
||||
" mode 0666 level user\n\n"
|
||||
"defaults\n"
|
||||
" log global\n"
|
||||
" retries 3\n"
|
||||
" option redispatch\n"
|
||||
" timeout connect 5000\n"
|
||||
" timeout client 50000\n"
|
||||
" timeout server 50000\n\n" + frontend + backend)
|
@ -31,3 +31,5 @@ pyOpenSSL>=0.11
|
||||
WSME>=0.6
|
||||
pyasn1
|
||||
pyasn1_modules
|
||||
|
||||
jinja2
|
||||
|
Loading…
Reference in New Issue
Block a user