Implement custom header support for Octavia
Implements support for custom header insertion in Octavia. A listener may be configured to insert custom headers which are supported by Octavia. Currently implemented support for X-Forwarded-For header, and X-Forwarded-Port Change-Id: I784f4939225c3acef362fcb5df57e77dbfb0f774
This commit is contained in:
parent
f629671974
commit
2194758bcf
|
@ -518,6 +518,9 @@ Listeners
|
||||||
+---------------------+------------+-------------------------------------+
|
+---------------------+------------+-------------------------------------+
|
||||||
| provisioning_status | String | Physical status of a listener |
|
| provisioning_status | String | Physical status of a listener |
|
||||||
+---------------------+------------+-------------------------------------+
|
+---------------------+------------+-------------------------------------+
|
||||||
|
| insert_headers | Dictionary | Dictionary of additional headers \ |
|
||||||
|
| | | insertion into HTTP header |
|
||||||
|
+---------------------+------------+-------------------------------------+
|
||||||
|
|
||||||
List Listeners
|
List Listeners
|
||||||
**************
|
**************
|
||||||
|
@ -649,6 +652,8 @@ Create a listener.
|
||||||
+------------------+----------+
|
+------------------+----------+
|
||||||
| enabled | no |
|
| enabled | no |
|
||||||
+------------------+----------+
|
+------------------+----------+
|
||||||
|
| insert_headers | no |
|
||||||
|
+------------------+----------+
|
||||||
|
|
||||||
**Request Example**::
|
**Request Example**::
|
||||||
|
|
||||||
|
@ -660,7 +665,8 @@ Create a listener.
|
||||||
'name': 'listener_name',
|
'name': 'listener_name',
|
||||||
'description': 'listener_description',
|
'description': 'listener_description',
|
||||||
'default_pool_id': 'uuid',
|
'default_pool_id': 'uuid',
|
||||||
'enabled': true
|
'enabled': true,
|
||||||
|
'insert_headers': {'X-Forwarded-For': 'true', 'X-Forwarded-Port': 'true'}
|
||||||
}
|
}
|
||||||
|
|
||||||
**Response Example**::
|
**Response Example**::
|
||||||
|
|
|
@ -111,6 +111,14 @@ class ListenersController(base.BaseController):
|
||||||
Update the load balancer db when provisioning status changes.
|
Update the load balancer db when provisioning status changes.
|
||||||
"""
|
"""
|
||||||
lb_repo = self.repositories.load_balancer
|
lb_repo = self.repositories.load_balancer
|
||||||
|
if (listener_dict
|
||||||
|
and listener_dict.get('insert_headers')
|
||||||
|
and list(set(listener_dict['insert_headers'].keys()) -
|
||||||
|
set(constants.SUPPORTED_HTTP_HEADERS))):
|
||||||
|
raise exceptions.InvalidOption(
|
||||||
|
value=listener_dict.get('insert_headers'),
|
||||||
|
option='insert_headers')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sni_containers = listener_dict.pop('sni_containers', [])
|
sni_containers = listener_dict.pop('sni_containers', [])
|
||||||
db_listener = self.repositories.listener.create(
|
db_listener = self.repositories.listener.create(
|
||||||
|
|
|
@ -44,6 +44,7 @@ class ListenerResponse(base.BaseType):
|
||||||
default_pool_id = wtypes.wsattr(wtypes.UuidType())
|
default_pool_id = wtypes.wsattr(wtypes.UuidType())
|
||||||
default_pool = wtypes.wsattr(pool.PoolResponse)
|
default_pool = wtypes.wsattr(pool.PoolResponse)
|
||||||
l7policies = wtypes.wsattr([l7policy.L7PolicyResponse])
|
l7policies = wtypes.wsattr([l7policy.L7PolicyResponse])
|
||||||
|
insert_headers = wtypes.wsattr(wtypes.DictType(str, str))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_data_model(cls, data_model, children=False):
|
def from_data_model(cls, data_model, children=False):
|
||||||
|
@ -90,6 +91,7 @@ class ListenerPOST(base.BaseType):
|
||||||
default_pool_id = wtypes.wsattr(wtypes.UuidType())
|
default_pool_id = wtypes.wsattr(wtypes.UuidType())
|
||||||
default_pool = wtypes.wsattr(pool.PoolPOST)
|
default_pool = wtypes.wsattr(pool.PoolPOST)
|
||||||
l7policies = wtypes.wsattr([l7policy.L7PolicyPOST], default=[])
|
l7policies = wtypes.wsattr([l7policy.L7PolicyPOST], default=[])
|
||||||
|
insert_headers = wtypes.wsattr(wtypes.DictType(str, str))
|
||||||
|
|
||||||
|
|
||||||
class ListenerPUT(base.BaseType):
|
class ListenerPUT(base.BaseType):
|
||||||
|
@ -104,3 +106,4 @@ class ListenerPUT(base.BaseType):
|
||||||
tls_termination = wtypes.wsattr(TLSTermination)
|
tls_termination = wtypes.wsattr(TLSTermination)
|
||||||
sni_containers = [wtypes.StringType(max_length=255)]
|
sni_containers = [wtypes.StringType(max_length=255)]
|
||||||
default_pool_id = wtypes.wsattr(wtypes.UuidType())
|
default_pool_id = wtypes.wsattr(wtypes.UuidType())
|
||||||
|
insert_headers = wtypes.wsattr(wtypes.DictType(str, str))
|
||||||
|
|
|
@ -308,5 +308,10 @@ API_VERSION = '0.5'
|
||||||
HAPROXY_BASE_PEER_PORT = 1025
|
HAPROXY_BASE_PEER_PORT = 1025
|
||||||
KEEPALIVED_CONF = 'keepalived.conf.j2'
|
KEEPALIVED_CONF = 'keepalived.conf.j2'
|
||||||
CHECK_SCRIPT_CONF = 'keepalived_check_script.conf.j2'
|
CHECK_SCRIPT_CONF = 'keepalived_check_script.conf.j2'
|
||||||
|
|
||||||
PLUGGED_INTERFACES = '/var/lib/octavia/plugged_interfaces'
|
PLUGGED_INTERFACES = '/var/lib/octavia/plugged_interfaces'
|
||||||
AMPHORA_NAMESPACE = 'amphora-haproxy'
|
AMPHORA_NAMESPACE = 'amphora-haproxy'
|
||||||
|
|
||||||
|
# List of HTTP headers which are supported for insertion
|
||||||
|
SUPPORTED_HTTP_HEADERS = ['X-Forwarded-For',
|
||||||
|
'X-Forwarded-Port']
|
||||||
|
|
|
@ -263,7 +263,7 @@ class Listener(BaseDataModel):
|
||||||
enabled=None, provisioning_status=None, operating_status=None,
|
enabled=None, provisioning_status=None, operating_status=None,
|
||||||
tls_certificate_id=None, stats=None, default_pool=None,
|
tls_certificate_id=None, stats=None, default_pool=None,
|
||||||
load_balancer=None, sni_containers=None, peer_port=None,
|
load_balancer=None, sni_containers=None, peer_port=None,
|
||||||
l7policies=None, pools=None):
|
l7policies=None, pools=None, insert_headers=None):
|
||||||
self.id = id
|
self.id = id
|
||||||
self.project_id = project_id
|
self.project_id = project_id
|
||||||
self.name = name
|
self.name = name
|
||||||
|
@ -283,6 +283,7 @@ class Listener(BaseDataModel):
|
||||||
self.sni_containers = sni_containers or []
|
self.sni_containers = sni_containers or []
|
||||||
self.peer_port = peer_port
|
self.peer_port = peer_port
|
||||||
self.l7policies = l7policies or []
|
self.l7policies = l7policies or []
|
||||||
|
self.insert_headers = insert_headers or {}
|
||||||
self.pools = pools or []
|
self.pools = pools or []
|
||||||
|
|
||||||
def update(self, update_dict):
|
def update(self, update_dict):
|
||||||
|
|
|
@ -167,6 +167,7 @@ class JinjaTemplater(object):
|
||||||
'protocol_mode': PROTOCOL_MAP[listener.protocol],
|
'protocol_mode': PROTOCOL_MAP[listener.protocol],
|
||||||
'protocol': listener.protocol,
|
'protocol': listener.protocol,
|
||||||
'peer_port': listener.peer_port,
|
'peer_port': listener.peer_port,
|
||||||
|
'insert_headers': listener.insert_headers,
|
||||||
'topology': listener.load_balancer.topology,
|
'topology': listener.load_balancer.topology,
|
||||||
'amphorae': listener.load_balancer.amphorae,
|
'amphorae': listener.load_balancer.amphorae,
|
||||||
'enabled': listener.enabled
|
'enabled': listener.enabled
|
||||||
|
|
|
@ -196,7 +196,14 @@ backend {{ pool.id }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if pool.protocol.lower() == constants.PROTOCOL_HTTP.lower() %}
|
{% if pool.protocol.lower() == constants.PROTOCOL_HTTP.lower() %}
|
||||||
|
{% if listener.insert_headers.get('X-Forwarded-For',
|
||||||
|
'False').lower() == 'true' %}
|
||||||
option forwardfor
|
option forwardfor
|
||||||
|
{% endif %}
|
||||||
|
{% if listener.insert_headers.get('X-Forwarded-Port',
|
||||||
|
'False').lower() == 'true' %}
|
||||||
|
http-request set-header X-Forwarded-Port %[dst_port]
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% for member in pool.members if member.enabled %}
|
{% for member in pool.members if member.enabled %}
|
||||||
{{- member_macro(constants, pool, member) -}}
|
{{- member_macro(constants, pool, member) -}}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Copyright 2016 VMware
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""Insert headers
|
||||||
|
|
||||||
|
Revision ID: 4d9cf7d32f2
|
||||||
|
Revises: 9bf4d21caaea
|
||||||
|
Create Date: 2016-02-21 17:16:22.316744
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '4d9cf7d32f2'
|
||||||
|
down_revision = '9bf4d21caaea'
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column('listener', sa.Column('insert_headers', sa.PickleType()))
|
|
@ -378,7 +378,9 @@ class Listener(base_models.BASE, base_models.IdMixin,
|
||||||
default_pool = orm.relationship("Pool", uselist=False,
|
default_pool = orm.relationship("Pool", uselist=False,
|
||||||
backref=orm.backref("_default_listeners",
|
backref=orm.backref("_default_listeners",
|
||||||
uselist=True))
|
uselist=True))
|
||||||
|
|
||||||
peer_port = sa.Column(sa.Integer(), nullable=True)
|
peer_port = sa.Column(sa.Integer(), nullable=True)
|
||||||
|
insert_headers = sa.Column(sa.PickleType())
|
||||||
|
|
||||||
# This property should be a unique list of the default_pool and anything
|
# This property should be a unique list of the default_pool and anything
|
||||||
# referenced by enabled L7Policies with at least one rule that also
|
# referenced by enabled L7Policies with at least one rule that also
|
||||||
|
|
|
@ -87,6 +87,7 @@ class TestListener(base.BaseAPITest):
|
||||||
'protocol_port': 80, 'connection_limit': 10,
|
'protocol_port': 80, 'connection_limit': 10,
|
||||||
'tls_certificate_id': uuidutils.generate_uuid(),
|
'tls_certificate_id': uuidutils.generate_uuid(),
|
||||||
'sni_containers': [sni1, sni2],
|
'sni_containers': [sni1, sni2],
|
||||||
|
'insert_headers': {},
|
||||||
'project_id': uuidutils.generate_uuid()}
|
'project_id': uuidutils.generate_uuid()}
|
||||||
lb_listener.update(optionals)
|
lb_listener.update(optionals)
|
||||||
response = self.post(self.listeners_path, lb_listener)
|
response = self.post(self.listeners_path, lb_listener)
|
||||||
|
@ -169,7 +170,8 @@ class TestListener(base.BaseAPITest):
|
||||||
defaults = {'name': None, 'default_pool_id': None,
|
defaults = {'name': None, 'default_pool_id': None,
|
||||||
'description': None, 'enabled': True,
|
'description': None, 'enabled': True,
|
||||||
'connection_limit': None, 'tls_certificate_id': None,
|
'connection_limit': None, 'tls_certificate_id': None,
|
||||||
'sni_containers': [], 'project_id': None}
|
'sni_containers': [], 'project_id': None,
|
||||||
|
'insert_headers': {}}
|
||||||
lb_listener = {'protocol': constants.PROTOCOL_HTTP,
|
lb_listener = {'protocol': constants.PROTOCOL_HTTP,
|
||||||
'protocol_port': 80}
|
'protocol_port': 80}
|
||||||
response = self.post(self.listeners_path, lb_listener)
|
response = self.post(self.listeners_path, lb_listener)
|
||||||
|
@ -395,3 +397,16 @@ class TestListener(base.BaseAPITest):
|
||||||
self.assertIsNone(listener.get('tls_termination'))
|
self.assertIsNone(listener.get('tls_termination'))
|
||||||
get_listener = self.get(listener_path).json
|
get_listener = self.get(listener_path).json
|
||||||
self.assertIsNone(get_listener.get('tls_termination'))
|
self.assertIsNone(get_listener.get('tls_termination'))
|
||||||
|
|
||||||
|
def test_create_with_valid_insert_headers(self):
|
||||||
|
lb_listener = {'protocol': 'HTTP',
|
||||||
|
'protocol_port': 80,
|
||||||
|
'insert_headers': {'X-Forwarded-For': 'true'}}
|
||||||
|
self.post(self.listeners_path, lb_listener, status=202)
|
||||||
|
|
||||||
|
def test_create_with_bad_insert_headers(self):
|
||||||
|
lb_listener = {'protocol': 'HTTP',
|
||||||
|
'protocol_port': 80,
|
||||||
|
# 'insert_headers': {'x': 'x'}}
|
||||||
|
'insert_headers': {'X-Forwarded-Four': 'true'}}
|
||||||
|
self.post(self.listeners_path, lb_listener, status=400)
|
||||||
|
|
|
@ -320,7 +320,8 @@ class TestLoadBalancerGraph(base.BaseAPITest):
|
||||||
'connection_limit': None,
|
'connection_limit': None,
|
||||||
'enabled': True,
|
'enabled': True,
|
||||||
'provisioning_status': constants.PENDING_CREATE,
|
'provisioning_status': constants.PENDING_CREATE,
|
||||||
'operating_status': constants.OFFLINE
|
'operating_status': constants.OFFLINE,
|
||||||
|
'insert_headers': {}
|
||||||
}
|
}
|
||||||
if create_sni_containers:
|
if create_sni_containers:
|
||||||
create_listener['sni_containers'] = create_sni_containers
|
create_listener['sni_containers'] = create_sni_containers
|
||||||
|
|
|
@ -47,7 +47,6 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
" timeout check 31\n"
|
" timeout check 31\n"
|
||||||
" option httpchk GET /index.html\n"
|
" option httpchk GET /index.html\n"
|
||||||
" http-check expect rstatus 418\n"
|
" http-check expect rstatus 418\n"
|
||||||
" option forwardfor\n"
|
|
||||||
" server sample_member_id_1 10.0.0.99:82 "
|
" server sample_member_id_1 10.0.0.99:82 "
|
||||||
"weight 13 check inter 30s fall 3 rise 2 "
|
"weight 13 check inter 30s fall 3 rise 2 "
|
||||||
"cookie sample_member_id_1\n"
|
"cookie sample_member_id_1\n"
|
||||||
|
@ -83,7 +82,6 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
" timeout check 31\n"
|
" timeout check 31\n"
|
||||||
" option httpchk GET /index.html\n"
|
" option httpchk GET /index.html\n"
|
||||||
" http-check expect rstatus 418\n"
|
" http-check expect rstatus 418\n"
|
||||||
" option forwardfor\n"
|
|
||||||
" server sample_member_id_1 10.0.0.99:82 "
|
" server sample_member_id_1 10.0.0.99:82 "
|
||||||
"weight 13 check inter 30s fall 3 rise 2 "
|
"weight 13 check inter 30s fall 3 rise 2 "
|
||||||
"cookie sample_member_id_1\n"
|
"cookie sample_member_id_1\n"
|
||||||
|
@ -110,7 +108,6 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
" timeout check 31\n"
|
" timeout check 31\n"
|
||||||
" option httpchk GET /index.html\n"
|
" option httpchk GET /index.html\n"
|
||||||
" http-check expect rstatus 418\n"
|
" http-check expect rstatus 418\n"
|
||||||
" option forwardfor\n"
|
|
||||||
" server sample_member_id_1 10.0.0.99:82 "
|
" server sample_member_id_1 10.0.0.99:82 "
|
||||||
"weight 13 check inter 30s fall 3 rise 2 "
|
"weight 13 check inter 30s fall 3 rise 2 "
|
||||||
"cookie sample_member_id_1\n"
|
"cookie sample_member_id_1\n"
|
||||||
|
@ -154,7 +151,6 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
" mode http\n"
|
" mode http\n"
|
||||||
" balance roundrobin\n"
|
" balance roundrobin\n"
|
||||||
" cookie SRV insert indirect nocache\n"
|
" cookie SRV insert indirect nocache\n"
|
||||||
" option forwardfor\n"
|
|
||||||
" server sample_member_id_1 10.0.0.99:82 weight 13 "
|
" server sample_member_id_1 10.0.0.99:82 weight 13 "
|
||||||
"cookie sample_member_id_1\n"
|
"cookie sample_member_id_1\n"
|
||||||
" server sample_member_id_2 10.0.0.98:82 weight 13 "
|
" server sample_member_id_2 10.0.0.98:82 weight 13 "
|
||||||
|
@ -206,7 +202,6 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
be = ("backend sample_pool_id_1\n"
|
be = ("backend sample_pool_id_1\n"
|
||||||
" mode http\n"
|
" mode http\n"
|
||||||
" balance roundrobin\n"
|
" balance roundrobin\n"
|
||||||
" option forwardfor\n"
|
|
||||||
" server sample_member_id_1 10.0.0.99:82 weight 13\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")
|
" server sample_member_id_2 10.0.0.98:82 weight 13\n\n")
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
|
@ -224,7 +219,6 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
" timeout check 31\n"
|
" timeout check 31\n"
|
||||||
" option httpchk GET /index.html\n"
|
" option httpchk GET /index.html\n"
|
||||||
" http-check expect rstatus 418\n"
|
" http-check expect rstatus 418\n"
|
||||||
" option forwardfor\n"
|
|
||||||
" server sample_member_id_1 10.0.0.99:82 "
|
" server sample_member_id_1 10.0.0.99:82 "
|
||||||
"weight 13 check inter 30s fall 3 rise 2\n"
|
"weight 13 check inter 30s fall 3 rise 2\n"
|
||||||
" server sample_member_id_2 10.0.0.98:82 "
|
" server sample_member_id_2 10.0.0.98:82 "
|
||||||
|
@ -246,7 +240,6 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
" timeout check 31\n"
|
" timeout check 31\n"
|
||||||
" option httpchk GET /index.html\n"
|
" option httpchk GET /index.html\n"
|
||||||
" http-check expect rstatus 418\n"
|
" http-check expect rstatus 418\n"
|
||||||
" option forwardfor\n"
|
|
||||||
" server sample_member_id_1 10.0.0.99:82 "
|
" server sample_member_id_1 10.0.0.99:82 "
|
||||||
"weight 13 check inter 30s fall 3 rise 2\n"
|
"weight 13 check inter 30s fall 3 rise 2\n"
|
||||||
" server sample_member_id_2 10.0.0.98:82 "
|
" server sample_member_id_2 10.0.0.98:82 "
|
||||||
|
@ -286,7 +279,6 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
" timeout check 31\n"
|
" timeout check 31\n"
|
||||||
" option httpchk GET /index.html\n"
|
" option httpchk GET /index.html\n"
|
||||||
" http-check expect rstatus 418\n"
|
" http-check expect rstatus 418\n"
|
||||||
" option forwardfor\n"
|
|
||||||
" server sample_member_id_1 10.0.0.99:82 weight 13 check "
|
" server sample_member_id_1 10.0.0.99:82 weight 13 check "
|
||||||
"inter 30s fall 3 rise 2 cookie sample_member_id_1\n"
|
"inter 30s fall 3 rise 2 cookie sample_member_id_1\n"
|
||||||
" server sample_member_id_2 10.0.0.98:82 weight 13 check "
|
" server sample_member_id_2 10.0.0.98:82 weight 13 check "
|
||||||
|
@ -299,7 +291,6 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
" timeout check 31\n"
|
" timeout check 31\n"
|
||||||
" option httpchk GET /healthmon.html\n"
|
" option httpchk GET /healthmon.html\n"
|
||||||
" http-check expect rstatus 418\n"
|
" http-check expect rstatus 418\n"
|
||||||
" option forwardfor\n"
|
|
||||||
" server sample_member_id_3 10.0.0.97:82 weight 13 check "
|
" server sample_member_id_3 10.0.0.97:82 weight 13 check "
|
||||||
"inter 30s fall 3 rise 2 cookie sample_member_id_3\n\n")
|
"inter 30s fall 3 rise 2 cookie sample_member_id_3\n\n")
|
||||||
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
|
@ -307,6 +298,52 @@ class TestHaproxyCfg(base.TestCase):
|
||||||
self.assertEqual(sample_configs.sample_base_expected_config(
|
self.assertEqual(sample_configs.sample_base_expected_config(
|
||||||
frontend=fe, backend=be), rendered_obj)
|
frontend=fe, backend=be), rendered_obj)
|
||||||
|
|
||||||
|
def test_render_template_http_xff(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 rise 2 "
|
||||||
|
"cookie sample_member_id_1\n"
|
||||||
|
" server sample_member_id_2 10.0.0.98:82 "
|
||||||
|
"weight 13 check inter 30s fall 3 rise 2 "
|
||||||
|
"cookie sample_member_id_2\n\n")
|
||||||
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
|
sample_configs.sample_listener_tuple(
|
||||||
|
insert_headers={'X-Forwarded-For': 'true'}))
|
||||||
|
self.assertEqual(
|
||||||
|
sample_configs.sample_base_expected_config(backend=be),
|
||||||
|
rendered_obj)
|
||||||
|
|
||||||
|
def test_render_template_http_xff_xfport(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"
|
||||||
|
" http-request set-header X-Forwarded-Port %[dst_port]\n"
|
||||||
|
" server sample_member_id_1 10.0.0.99:82 "
|
||||||
|
"weight 13 check inter 30s fall 3 rise 2 "
|
||||||
|
"cookie sample_member_id_1\n"
|
||||||
|
" server sample_member_id_2 10.0.0.98:82 "
|
||||||
|
"weight 13 check inter 30s fall 3 rise 2 "
|
||||||
|
"cookie sample_member_id_2\n\n")
|
||||||
|
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
|
||||||
|
sample_configs.sample_listener_tuple(
|
||||||
|
insert_headers={'X-Forwarded-For': 'true',
|
||||||
|
'X-Forwarded-Port': 'true'}))
|
||||||
|
self.assertEqual(
|
||||||
|
sample_configs.sample_base_expected_config(backend=be),
|
||||||
|
rendered_obj)
|
||||||
|
|
||||||
def test_transform_session_persistence(self):
|
def test_transform_session_persistence(self):
|
||||||
in_persistence = sample_configs.sample_session_persistence_tuple()
|
in_persistence = sample_configs.sample_session_persistence_tuple()
|
||||||
ret = self.jinja_cfg._transform_session_persistence(in_persistence)
|
ret = self.jinja_cfg._transform_session_persistence(in_persistence)
|
||||||
|
|
|
@ -204,7 +204,8 @@ RET_LISTENER = {
|
||||||
'topology': 'SINGLE',
|
'topology': 'SINGLE',
|
||||||
'pools': [RET_POOL_1],
|
'pools': [RET_POOL_1],
|
||||||
'l7policies': [],
|
'l7policies': [],
|
||||||
'enabled': True}
|
'enabled': True,
|
||||||
|
'insert_headers': {}}
|
||||||
|
|
||||||
RET_LISTENER_L7 = {
|
RET_LISTENER_L7 = {
|
||||||
'id': 'sample_listener_id_1',
|
'id': 'sample_listener_id_1',
|
||||||
|
@ -219,7 +220,8 @@ RET_LISTENER_L7 = {
|
||||||
'pools': [RET_POOL_1, RET_POOL_2],
|
'pools': [RET_POOL_1, RET_POOL_2],
|
||||||
'l7policies': [RET_L7POLICY_1, RET_L7POLICY_2, RET_L7POLICY_3,
|
'l7policies': [RET_L7POLICY_1, RET_L7POLICY_2, RET_L7POLICY_3,
|
||||||
RET_L7POLICY_4, RET_L7POLICY_5],
|
RET_L7POLICY_4, RET_L7POLICY_5],
|
||||||
'enabled': True}
|
'enabled': True,
|
||||||
|
'insert_headers': {}}
|
||||||
|
|
||||||
RET_LISTENER_TLS = {
|
RET_LISTENER_TLS = {
|
||||||
'id': 'sample_listener_id_1',
|
'id': 'sample_listener_id_1',
|
||||||
|
@ -233,7 +235,8 @@ RET_LISTENER_TLS = {
|
||||||
'default_tls_container': RET_DEF_TLS_CONT,
|
'default_tls_container': RET_DEF_TLS_CONT,
|
||||||
'pools': [RET_POOL_1],
|
'pools': [RET_POOL_1],
|
||||||
'l7policies': [],
|
'l7policies': [],
|
||||||
'enabled': True}
|
'enabled': True,
|
||||||
|
'insert_headers': {}}
|
||||||
|
|
||||||
RET_LISTENER_TLS_SNI = {
|
RET_LISTENER_TLS_SNI = {
|
||||||
'id': 'sample_listener_id_1',
|
'id': 'sample_listener_id_1',
|
||||||
|
@ -250,7 +253,8 @@ RET_LISTENER_TLS_SNI = {
|
||||||
'sni_containers': [RET_SNI_CONT_1, RET_SNI_CONT_2],
|
'sni_containers': [RET_SNI_CONT_1, RET_SNI_CONT_2],
|
||||||
'pools': [RET_POOL_1],
|
'pools': [RET_POOL_1],
|
||||||
'l7policies': [],
|
'l7policies': [],
|
||||||
'enabled': True}
|
'enabled': True,
|
||||||
|
'insert_headers': {}}
|
||||||
|
|
||||||
RET_LB = {
|
RET_LB = {
|
||||||
'name': 'test-lb',
|
'name': 'test-lb',
|
||||||
|
@ -345,18 +349,19 @@ def sample_vip_tuple():
|
||||||
def sample_listener_tuple(proto=None, monitor=True, persistence=True,
|
def sample_listener_tuple(proto=None, monitor=True, persistence=True,
|
||||||
persistence_type=None, persistence_cookie=None,
|
persistence_type=None, persistence_cookie=None,
|
||||||
tls=False, sni=False, peer_port=None, topology=None,
|
tls=False, sni=False, peer_port=None, topology=None,
|
||||||
l7=False, enabled=True):
|
l7=False, enabled=True, insert_headers=None):
|
||||||
proto = 'HTTP' if proto is None else proto
|
proto = 'HTTP' if proto is None else proto
|
||||||
be_proto = 'HTTP' if proto is 'TERMINATED_HTTPS' else proto
|
be_proto = 'HTTP' if proto is 'TERMINATED_HTTPS' else proto
|
||||||
topology = 'SINGLE' if topology is None else topology
|
topology = 'SINGLE' if topology is None else topology
|
||||||
port = '443' if proto is 'HTTPS' or proto is 'TERMINATED_HTTPS' else '80'
|
port = '443' if proto is 'HTTPS' or proto is 'TERMINATED_HTTPS' else '80'
|
||||||
peer_port = 1024 if peer_port is None else peer_port
|
peer_port = 1024 if peer_port is None else peer_port
|
||||||
|
insert_headers = insert_headers or {}
|
||||||
in_listener = collections.namedtuple(
|
in_listener = collections.namedtuple(
|
||||||
'listener', 'id, project_id, protocol_port, protocol, default_pool, '
|
'listener', 'id, project_id, protocol_port, protocol, default_pool, '
|
||||||
'connection_limit, tls_certificate_id, '
|
'connection_limit, tls_certificate_id, '
|
||||||
'sni_container_ids, default_tls_container, '
|
'sni_container_ids, default_tls_container, '
|
||||||
'sni_containers, load_balancer, peer_port, pools, '
|
'sni_containers, load_balancer, peer_port, pools, '
|
||||||
'l7policies, enabled',)
|
'l7policies, enabled, insert_headers',)
|
||||||
if l7:
|
if l7:
|
||||||
pools = [
|
pools = [
|
||||||
sample_pool_tuple(
|
sample_pool_tuple(
|
||||||
|
@ -419,7 +424,8 @@ def sample_listener_tuple(proto=None, monitor=True, persistence=True,
|
||||||
if sni else [],
|
if sni else [],
|
||||||
pools=pools,
|
pools=pools,
|
||||||
l7policies=l7policies,
|
l7policies=l7policies,
|
||||||
enabled=enabled
|
enabled=enabled,
|
||||||
|
insert_headers=insert_headers
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -615,7 +621,6 @@ def sample_base_expected_config(frontend=None, backend=None, peers=None):
|
||||||
" timeout check 31\n"
|
" timeout check 31\n"
|
||||||
" option httpchk GET /index.html\n"
|
" option httpchk GET /index.html\n"
|
||||||
" http-check expect rstatus 418\n"
|
" http-check expect rstatus 418\n"
|
||||||
" option forwardfor\n"
|
|
||||||
" server sample_member_id_1 10.0.0.99:82 weight 13 "
|
" server sample_member_id_1 10.0.0.99:82 weight 13 "
|
||||||
"check inter 30s fall 3 rise 2 cookie sample_member_id_1\n"
|
"check inter 30s fall 3 rise 2 cookie sample_member_id_1\n"
|
||||||
" server sample_member_id_2 10.0.0.98:82 weight 13 "
|
" server sample_member_id_2 10.0.0.98:82 weight 13 "
|
||||||
|
|
Loading…
Reference in New Issue