Expose timeout options

Various timeout options need to be exposed to enable use-cases more
complex than standard HTTP requests.

In this patch we expose four new timeout values:
* timeout_client_data
* timeout_member_connect
* timeout_member_data
* timeout_tcp_inspect

Change-Id: Id4667201c1bfaa06f7af9060c936ba00c2f314f9
Story: 1457556
Task: 5453
This commit is contained in:
Adam Harwell 2018-03-23 05:58:12 +09:00
parent e819e4521a
commit bb0447e98b
26 changed files with 512 additions and 65 deletions

View File

@ -1029,6 +1029,56 @@ subnet_id-optional:
in: body
required: false
type: uuid
timeout_client_data:
description: |
Frontend client inactivity timeout in milliseconds. Default: 50000.
in: body
required: true
type: integer
timeout_client_data-optional:
description: |
Frontend client inactivity timeout in milliseconds. Default: 50000.
in: body
required: false
type: integer
timeout_member_connect:
description: |
Backend member connection timeout in milliseconds. Default: 5000.
in: body
required: true
type: integer
timeout_member_connect-optional:
description: |
Backend member connection timeout in milliseconds. Default: 5000.
in: body
required: false
type: integer
timeout_member_data:
description: |
Backend member inactivity timeout in milliseconds. Default: 50000.
in: body
required: true
type: integer
timeout_member_data-optional:
description: |
Backend member inactivity timeout in milliseconds. Default: 50000.
in: body
required: false
type: integer
timeout_tcp_inspect:
description: |
Time, in milliseconds, to wait for additional TCP packets for content
inspection. Default: 0.
in: body
required: true
type: integer
timeout_tcp_inspect-optional:
description: |
Time, in milliseconds, to wait for additional TCP packets for content
inspection. Default: 0.
in: body
required: false
type: integer
total_connections:
description: |
The total connections handled.

View File

@ -1 +1 @@
curl -X POST -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"listener": {"protocol": "TERMINATED_HTTPS", "description": "A great TLS listener", "admin_state_up": true, "connection_limit": 200, "protocol_port": "443", "loadbalancer_id": "607226db-27ef-4d41-ae89-f2a800e9c2db", "name": "great_tls_listener", "insert_headers": {"X-Forwarded-For": "true", "X-Forwarded-Port": "true"}, "default_tls_container_ref": "http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "sni_container_refs": ["http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "http://198.51.100.10:9311/v1/containers/aaebb31e-7761-4826-8cb4-2b829caca3ee"]}}' http://198.51.100.10:9876/v2.0/lbaas/listeners
curl -X POST -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"listener": {"protocol": "TERMINATED_HTTPS", "description": "A great TLS listener", "admin_state_up": true, "connection_limit": 200, "protocol_port": "443", "loadbalancer_id": "607226db-27ef-4d41-ae89-f2a800e9c2db", "name": "great_tls_listener", "insert_headers": {"X-Forwarded-For": "true", "X-Forwarded-Port": "true"}, "default_tls_container_ref": "http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "sni_container_refs": ["http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "http://198.51.100.10:9311/v1/containers/aaebb31e-7761-4826-8cb4-2b829caca3ee"], "timeout_client_data": 50000, "timeout_member_connect": 5000, "timeout_member_data": 50000, "timeout_tcp_inspect": 0}}' http://198.51.100.10:9876/v2.0/lbaas/listeners

View File

@ -15,6 +15,10 @@
"sni_container_refs": [
"http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51",
"http://198.51.100.10:9311/v1/containers/aaebb31e-7761-4826-8cb4-2b829caca3ee"
]
],
"timeout_client_data": 50000,
"timeout_member_connect": 5000,
"timeout_member_data": 50000,
"timeout_tcp_inspect": 0
}
}

View File

@ -30,6 +30,10 @@
"id": "5e618272-339d-4a80-8d14-dbc093091bb1"
}
],
"name": "great_tls_listener"
"name": "great_tls_listener",
"timeout_client_data": 50000,
"timeout_member_connect": 5000,
"timeout_member_data": 50000,
"timeout_tcp_inspect": 0
}
}

View File

@ -30,6 +30,10 @@
"id": "5e618272-339d-4a80-8d14-dbc093091bb1"
}
],
"name": "great_tls_listener"
"name": "great_tls_listener",
"timeout_client_data": 50000,
"timeout_member_connect": 5000,
"timeout_member_data": 50000,
"timeout_tcp_inspect": 0
}
}

View File

@ -1 +1 @@
curl -X PUT -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"listener": {"description": "An updated great TLS listener", "admin_state_up": true, "connection_limit": 200, "name": "great_updated_tls_listener", "insert_headers": {"X-Forwarded-For": "false", "X-Forwarded-Port": "true"}, "default_tls_container_ref": "http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "sni_container_refs": ["http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "http://198.51.100.10:9311/v1/containers/aaebb31e-7761-4826-8cb4-2b829caca3ee"]}}' http://198.51.100.10:9876/v2.0/lbaas/listeners/023f2e34-7806-443b-bfae-16c324569a3d
curl -X PUT -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"listener": {"description": "An updated great TLS listener", "admin_state_up": true, "connection_limit": 200, "name": "great_updated_tls_listener", "insert_headers": {"X-Forwarded-For": "false", "X-Forwarded-Port": "true"}, "default_tls_container_ref": "http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "sni_container_refs": ["http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51", "http://198.51.100.10:9311/v1/containers/aaebb31e-7761-4826-8cb4-2b829caca3ee"], "timeout_client_data": 100000, "timeout_member_connect": 1000, "timeout_member_data": 100000, "timeout_tcp_inspect": 5}}' http://198.51.100.10:9876/v2.0/lbaas/listeners/023f2e34-7806-443b-bfae-16c324569a3d

View File

@ -13,6 +13,10 @@
"sni_container_refs": [
"http://198.51.100.10:9311/v1/containers/a570068c-d295-4780-91d4-3046a325db51",
"http://198.51.100.10:9311/v1/containers/aaebb31e-7761-4826-8cb4-2b829caca3ee"
]
],
"timeout_client_data": 100000,
"timeout_member_connect": 1000,
"timeout_member_data": 100000,
"timeout_tcp_inspect": 5
}
}

View File

@ -30,6 +30,10 @@
"id": "5e618272-339d-4a80-8d14-dbc093091bb1"
}
],
"name": "great_updated_tls_listener"
"name": "great_updated_tls_listener",
"timeout_client_data": 100000,
"timeout_member_connect": 1000,
"timeout_member_data": 100000,
"timeout_tcp_inspect": 5
}
}

View File

@ -32,7 +32,11 @@
"id": "5e618272-339d-4a80-8d14-dbc093091bb1"
}
],
"name": "great_tls_listener"
"name": "great_tls_listener",
"timeout_client_data": 50000,
"timeout_member_connect": 5000,
"timeout_member_data": 50000,
"timeout_tcp_inspect": 0
}
]
}

View File

@ -63,6 +63,10 @@ Response Parameters
- protocol_port: protocol_port
- provisioning_status: provisioning_status
- sni_container_refs: sni_container_refs
- timeout_client_data: timeout_client_data
- timeout_member_connect: timeout_member_connect
- timeout_member_data: timeout_member_data
- timeout_tcp_inspect: timeout_tcp_inspect
- updated_at: updated_at
Response Example
@ -145,6 +149,10 @@ Request
- protocol: protocol
- protocol_port: protocol_port
- sni_container_refs: sni_container_refs-optional
- timeout_client_data: timeout_client_data-optional
- timeout_member_connect: timeout_member_connect-optional
- timeout_member_data: timeout_member_data-optional
- timeout_tcp_inspect: timeout_tcp_inspect-optional
.. _header_insertions:
@ -204,6 +212,10 @@ Response Parameters
- protocol_port: protocol_port
- provisioning_status: provisioning_status
- sni_container_refs: sni_container_refs
- timeout_client_data: timeout_client_data
- timeout_member_connect: timeout_member_connect
- timeout_member_data: timeout_member_data
- timeout_tcp_inspect: timeout_tcp_inspect
- updated_at: updated_at
Response Example
@ -273,6 +285,10 @@ Response Parameters
- protocol_port: protocol_port
- provisioning_status: provisioning_status
- sni_container_refs: sni_container_refs
- timeout_client_data: timeout_client_data
- timeout_member_connect: timeout_member_connect
- timeout_member_data: timeout_member_data
- timeout_tcp_inspect: timeout_tcp_inspect
- updated_at: updated_at
Response Example
@ -323,6 +339,10 @@ Request
- listener_id: path-listener-id
- name: name-optional
- sni_container_refs: sni_container_refs-optional
- timeout_client_data: timeout_client_data-optional
- timeout_member_connect: timeout_member_connect-optional
- timeout_member_data: timeout_member_data-optional
- timeout_tcp_inspect: timeout_tcp_inspect-optional
Request Example
---------------
@ -359,6 +379,10 @@ Response Parameters
- protocol_port: protocol_port
- provisioning_status: provisioning_status
- sni_container_refs: sni_container_refs
- timeout_client_data: timeout_client_data
- timeout_member_connect: timeout_member_connect
- timeout_member_data: timeout_member_data
- timeout_tcp_inspect: timeout_tcp_inspect
- updated_at: updated_at
Response Example

View File

@ -49,7 +49,7 @@ class RootController(rest.RestController):
self._versions.append(
{
'status': 'CURRENT',
'updated': '2018-03-14T00:00:00Z',
'updated': '2018-03-23T00:00:00Z',
'id': 'v2.0'
})
if not (v1_enabled or v2_enabled):

View File

@ -46,6 +46,10 @@ class ListenerResponse(BaseListenerType):
created_at = wtypes.wsattr(wtypes.datetime.datetime)
updated_at = wtypes.wsattr(wtypes.datetime.datetime)
loadbalancers = wtypes.wsattr([types.IdOnlyType])
timeout_client_data = wtypes.wsattr(wtypes.IntegerType())
timeout_member_connect = wtypes.wsattr(wtypes.IntegerType())
timeout_member_data = wtypes.wsattr(wtypes.IntegerType())
timeout_tcp_inspect = wtypes.wsattr(wtypes.IntegerType())
@classmethod
def from_data_model(cls, data_model, children=False):
@ -109,6 +113,22 @@ class ListenerPOST(BaseListenerType):
insert_headers = wtypes.wsattr(
wtypes.DictType(str, wtypes.StringType(max_length=255)))
loadbalancer_id = wtypes.wsattr(wtypes.UuidType(), mandatory=True)
timeout_client_data = wtypes.wsattr(
wtypes.IntegerType(minimum=constants.MIN_TIMEOUT,
maximum=constants.MAX_TIMEOUT),
default=constants.DEFAULT_TIMEOUT_CLIENT_DATA)
timeout_member_connect = wtypes.wsattr(
wtypes.IntegerType(minimum=constants.MIN_TIMEOUT,
maximum=constants.MAX_TIMEOUT),
default=constants.DEFAULT_TIMEOUT_MEMBER_CONNECT)
timeout_member_data = wtypes.wsattr(
wtypes.IntegerType(minimum=constants.MIN_TIMEOUT,
maximum=constants.MAX_TIMEOUT),
default=constants.DEFAULT_TIMEOUT_MEMBER_DATA)
timeout_tcp_inspect = wtypes.wsattr(
wtypes.IntegerType(minimum=constants.MIN_TIMEOUT,
maximum=constants.MAX_TIMEOUT),
default=constants.DEFAULT_TIMEOUT_TCP_INSPECT)
class ListenerRootPOST(types.BaseType):
@ -128,6 +148,18 @@ class ListenerPUT(BaseListenerType):
default_pool_id = wtypes.wsattr(wtypes.UuidType())
insert_headers = wtypes.wsattr(
wtypes.DictType(str, wtypes.StringType(max_length=255)))
timeout_client_data = wtypes.wsattr(
wtypes.IntegerType(minimum=constants.MIN_TIMEOUT,
maximum=constants.MAX_TIMEOUT))
timeout_member_connect = wtypes.wsattr(
wtypes.IntegerType(minimum=constants.MIN_TIMEOUT,
maximum=constants.MAX_TIMEOUT))
timeout_member_data = wtypes.wsattr(
wtypes.IntegerType(minimum=constants.MIN_TIMEOUT,
maximum=constants.MAX_TIMEOUT))
timeout_tcp_inspect = wtypes.wsattr(
wtypes.IntegerType(minimum=constants.MIN_TIMEOUT,
maximum=constants.MAX_TIMEOUT))
class ListenerRootPUT(types.BaseType):
@ -154,6 +186,22 @@ class ListenerSingleCreate(BaseListenerType):
l7policies = wtypes.wsattr([l7policy.L7PolicySingleCreate], default=[])
insert_headers = wtypes.wsattr(
wtypes.DictType(str, wtypes.StringType(max_length=255)))
timeout_client_data = wtypes.wsattr(
wtypes.IntegerType(minimum=constants.MIN_TIMEOUT,
maximum=constants.MAX_TIMEOUT),
default=constants.DEFAULT_TIMEOUT_CLIENT_DATA)
timeout_member_connect = wtypes.wsattr(
wtypes.IntegerType(minimum=constants.MIN_TIMEOUT,
maximum=constants.MAX_TIMEOUT),
default=constants.DEFAULT_TIMEOUT_MEMBER_CONNECT)
timeout_member_data = wtypes.wsattr(
wtypes.IntegerType(minimum=constants.MIN_TIMEOUT,
maximum=constants.MAX_TIMEOUT),
default=constants.DEFAULT_TIMEOUT_MEMBER_DATA)
timeout_tcp_inspect = wtypes.wsattr(
wtypes.IntegerType(minimum=constants.MIN_TIMEOUT,
maximum=constants.MAX_TIMEOUT),
default=constants.DEFAULT_TIMEOUT_TCP_INSPECT)
class ListenerStatusResponse(BaseListenerType):

View File

@ -76,6 +76,15 @@ MAX_WEIGHT = 256
MIN_HM_RETRIES = 1
MAX_HM_RETRIES = 10
# 1 year: y d h m ms
MAX_TIMEOUT = 365 * 24 * 60 * 60 * 1000
MIN_TIMEOUT = 0
DEFAULT_TIMEOUT_CLIENT_DATA = 50000
DEFAULT_TIMEOUT_MEMBER_CONNECT = 5000
DEFAULT_TIMEOUT_MEMBER_DATA = 50000
DEFAULT_TIMEOUT_TCP_INSPECT = 0
# Note: The database Amphora table has a foreign key constraint against
# the provisioning_status table
# Amphora has been allocated to a load balancer

View File

@ -351,7 +351,9 @@ class Listener(BaseDataModel):
tls_certificate_id=None, stats=None, default_pool=None,
load_balancer=None, sni_containers=None, peer_port=None,
l7policies=None, pools=None, insert_headers=None,
created_at=None, updated_at=None):
created_at=None, updated_at=None,
timeout_client_data=None, timeout_member_connect=None,
timeout_member_data=None, timeout_tcp_inspect=None):
self.id = id
self.project_id = project_id
self.name = name
@ -375,6 +377,10 @@ class Listener(BaseDataModel):
self.pools = pools or []
self.created_at = created_at
self.updated_at = updated_at
self.timeout_client_data = timeout_client_data
self.timeout_member_connect = timeout_member_connect
self.timeout_member_data = timeout_member_data
self.timeout_tcp_inspect = timeout_tcp_inspect
def update(self, update_dict):
for key, value in update_dict.items():

View File

@ -58,10 +58,7 @@ class JinjaTemplater(object):
base_crt_dir=None,
haproxy_template=None,
log_http=None,
log_server=None,
timeout_client=None,
timeout_server=None,
timeout_connect=None):
log_server=None):
"""HaProxy configuration generation
:param base_amp_path: Base path for amphora data
@ -69,9 +66,6 @@ class JinjaTemplater(object):
:param haproxy_template: Absolute path to Jinja template
:param log_http: Haproxy HTTP logging path
:param log_server: Haproxy Server logging path
:param timeout_client: Timeout client
:param timeout_server: Timeout server
:param timeout_connect: Timeout connect
"""
self.base_amp_path = base_amp_path or BASE_PATH
@ -79,9 +73,6 @@ class JinjaTemplater(object):
self.haproxy_template = haproxy_template or HAPROXY_TEMPLATE
self.log_http = log_http
self.log_server = log_server
self.timeout_client = timeout_client
self.timeout_server = timeout_server
self.timeout_connect = timeout_connect
def build_config(self, host_amphora, listener, tls_cert,
socket_path=None,
@ -139,10 +130,7 @@ class JinjaTemplater(object):
'user_group': user_group,
'stats_sock': socket_path,
'log_http': self.log_http,
'log_server': self.log_server,
'timeout_client': self.timeout_client,
'timeout_server': self.timeout_server,
'timeout_connect': self.timeout_connect},
'log_server': self.log_server},
constants=constants)
def _transform_loadbalancer(self, host_amphora, loadbalancer, listener,
@ -200,7 +188,16 @@ class JinjaTemplater(object):
'insert_headers': listener.insert_headers,
'topology': listener.load_balancer.topology,
'amphorae': listener.load_balancer.amphorae,
'enabled': listener.enabled
'enabled': listener.enabled,
'timeout_client_data': (listener.timeout_client_data or
constants.DEFAULT_TIMEOUT_CLIENT_DATA),
'timeout_member_connect': (listener.timeout_member_connect or
constants.DEFAULT_TIMEOUT_MEMBER_CONNECT
),
'timeout_member_data': (listener.timeout_member_data or
constants.DEFAULT_TIMEOUT_MEMBER_DATA),
'timeout_tcp_inspect': (listener.timeout_tcp_inspect or
constants.DEFAULT_TIMEOUT_TCP_INSPECT),
}
if listener.connection_limit and listener.connection_limit > -1:
ret_value['connection_limit'] = listener.connection_limit

View File

@ -38,9 +38,6 @@ defaults
log global
retries 3
option redispatch
timeout connect {{ timeout_connect | default('5000', true) }}
timeout client {{ timeout_client | default('50000', true) }}
timeout server {{ timeout_server | default('50000', true) }}
{% block peers %}{% endblock peers %}

View File

@ -136,6 +136,10 @@ frontend {{ listener.id }}
{% if listener.default_pool and listener.default_pool.enabled %}
default_backend {{ listener.default_pool.id }}
{% endif %}
timeout client {{ listener.timeout_client_data }}
{% if listener.timeout_tcp_inspect %}
tcp-request inspect-delay {{ listener.timeout_tcp_inspect }}
{% endif %}
{% endmacro %}
@ -251,6 +255,8 @@ backend {{ pool.id }}
fullconn {{ listener.connection_limit }}
{% endif %}
option allbackups
timeout connect {{ listener.timeout_member_connect }}
timeout server {{ listener.timeout_member_data }}
{% for member in pool.members if member.enabled %}
{{- member_macro(constants, pool, member) -}}
{% endfor %}

View File

@ -0,0 +1,50 @@
# Copyright 2018 GoDaddy
#
# 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.
#
"""add timeout fields to listener
Revision ID: 0fd2c131923f
Revises: ba35e0fb88e1
Create Date: 2018-03-23 03:34:26.657254
"""
from alembic import op
import sqlalchemy as sa
from octavia.common import constants
# revision identifiers, used by Alembic.
revision = '0fd2c131923f'
down_revision = 'ba35e0fb88e1'
def upgrade():
op.add_column('listener',
sa.Column('timeout_client_data',
sa.Integer(), nullable=True,
default=constants.DEFAULT_TIMEOUT_CLIENT_DATA))
op.add_column('listener',
sa.Column('timeout_member_connect',
sa.Integer(), nullable=True,
default=constants.DEFAULT_TIMEOUT_MEMBER_CONNECT))
op.add_column('listener',
sa.Column('timeout_member_data',
sa.Integer(), nullable=True,
default=constants.DEFAULT_TIMEOUT_MEMBER_DATA))
op.add_column('listener',
sa.Column('timeout_tcp_inspect',
sa.Integer(), nullable=True,
default=constants.DEFAULT_TIMEOUT_TCP_INSPECT))

View File

@ -442,6 +442,10 @@ class Listener(base_models.BASE, base_models.IdMixin,
peer_port = sa.Column(sa.Integer(), nullable=True)
insert_headers = sa.Column(sa.PickleType())
timeout_client_data = sa.Column(sa.Integer, nullable=True)
timeout_member_connect = sa.Column(sa.Integer, nullable=True)
timeout_member_data = sa.Column(sa.Integer, nullable=True)
timeout_tcp_inspect = sa.Column(sa.Integer, nullable=True)
# This property should be a unique list of the default_pool and anything
# referenced by enabled L7Policies with at least one rule that also

View File

@ -424,7 +424,7 @@ class TestListener(base.BaseAPITest):
listener_path = self.listener_path
self.get(listener_path.format(listener_id='SEAN-CONNERY'), status=404)
def test_create(self, **optionals):
def test_create(self, response_status=201, **optionals):
sni1 = uuidutils.generate_uuid()
sni2 = uuidutils.generate_uuid()
lb_listener = {'name': 'listener1', 'default_pool_id': None,
@ -439,7 +439,9 @@ class TestListener(base.BaseAPITest):
'loadbalancer_id': self.lb_id}
lb_listener.update(optionals)
body = self._build_body(lb_listener)
response = self.post(self.LISTENERS_PATH, body)
response = self.post(self.LISTENERS_PATH, body, status=response_status)
if response_status >= 300:
return response
listener_api = response.json['listener']
extra_expects = {'provisioning_status': constants.PENDING_CREATE,
'operating_status': constants.OFFLINE}
@ -460,6 +462,52 @@ class TestListener(base.BaseAPITest):
self.assert_correct_lb_status(self.lb_id, constants.ONLINE,
constants.PENDING_UPDATE)
self.assert_final_listener_statuses(self.lb_id, listener_api.get('id'))
return listener_api
def test_create_with_timeouts(self):
optionals = {
'timeout_client_data': 1,
'timeout_member_connect': 2,
'timeout_member_data': constants.MIN_TIMEOUT,
'timeout_tcp_inspect': constants.MAX_TIMEOUT,
}
listener_api = self.test_create(**optionals)
self.assertEqual(1, listener_api.get('timeout_client_data'))
self.assertEqual(2, listener_api.get('timeout_member_connect'))
self.assertEqual(constants.MIN_TIMEOUT,
listener_api.get('timeout_member_data'))
self.assertEqual(constants.MAX_TIMEOUT,
listener_api.get('timeout_tcp_inspect'))
def test_create_with_timeouts_too_high(self):
optionals = {
'timeout_client_data': 1,
'timeout_member_connect': 2,
'timeout_member_data': 3,
'timeout_tcp_inspect': constants.MAX_TIMEOUT + 1,
}
resp = self.test_create(response_status=400, **optionals).json
fault = resp.get('faultstring')
self.assertIn(
'Invalid input for field/attribute timeout_tcp_inspect', fault)
self.assertIn(
'Value should be lower or equal to {0}'.format(
constants.MAX_TIMEOUT), fault)
def test_create_with_timeouts_too_low(self):
optionals = {
'timeout_client_data': 1,
'timeout_member_connect': 2,
'timeout_member_data': 3,
'timeout_tcp_inspect': constants.MIN_TIMEOUT - 1,
}
resp = self.test_create(response_status=400, **optionals).json
fault = resp.get('faultstring')
self.assertIn(
'Invalid input for field/attribute timeout_tcp_inspect', fault)
self.assertIn(
'Value should be greater or equal to {0}'.format(
constants.MIN_TIMEOUT), fault)
def test_create_duplicate_fails(self):
self.create_listener(constants.PROTOCOL_HTTP, 80, self.lb_id)
@ -720,15 +768,18 @@ class TestListener(base.BaseAPITest):
default_pool_id=None).get(self.root_tag)
self.set_lb_status(self.lb_id)
new_listener = {'name': 'listener2', 'admin_state_up': True,
'default_pool_id': self.pool_id}
'default_pool_id': self.pool_id,
'timeout_client_data': 1,
'timeout_member_connect': 2,
'timeout_member_data': 3,
'timeout_tcp_inspect': 4}
body = self._build_body(new_listener)
listener_path = self.LISTENER_PATH.format(
listener_id=listener['id'])
api_listener = self.put(listener_path, body).json.get(self.root_tag)
update_expect = {'name': 'listener2', 'admin_state_up': True,
'default_pool_id': self.pool_id,
'provisioning_status': constants.PENDING_UPDATE,
update_expect = {'provisioning_status': constants.PENDING_UPDATE,
'operating_status': constants.ONLINE}
update_expect.update(new_listener)
listener.update(update_expect)
self.assertEqual(listener['created_at'], api_listener['created_at'])
self.assertNotEqual(listener['updated_at'], api_listener['updated_at'])

View File

@ -1941,7 +1941,11 @@ class TestLoadBalancerGraph(base.BaseAPITest):
'provisioning_status': constants.PENDING_CREATE,
'operating_status': constants.OFFLINE,
'insert_headers': {},
'project_id': self._project_id
'project_id': self._project_id,
'timeout_client_data': constants.DEFAULT_TIMEOUT_CLIENT_DATA,
'timeout_member_connect': constants.DEFAULT_TIMEOUT_MEMBER_CONNECT,
'timeout_member_data': constants.DEFAULT_TIMEOUT_MEMBER_DATA,
'timeout_tcp_inspect': constants.DEFAULT_TIMEOUT_TCP_INSPECT,
}
if create_sni_containers:
create_listener['sni_container_refs'] = create_sni_containers

View File

@ -335,6 +335,17 @@ class ListenerModelTest(base.OctaviaDBTestBase, ModelTestMixin):
self.assertIsNotNone(listener.created_at)
self.assertIsNone(listener.updated_at)
def test_create_with_timeouts(self):
timeouts = {
'timeout_client_data': 1,
'timeout_member_connect': 2,
'timeout_member_data': constants.MIN_TIMEOUT,
'timeout_tcp_inspect': constants.MAX_TIMEOUT,
}
listener = self.create_listener(self.session, **timeouts)
for item in timeouts:
self.assertEqual(timeouts[item], getattr(listener, item))
def test_update(self):
listener = self.create_listener(self.session)
self.assertIsNone(listener.updated_at)
@ -346,6 +357,24 @@ class ListenerModelTest(base.OctaviaDBTestBase, ModelTestMixin):
self.assertEqual('test1', new_listener.name)
self.assertIsNotNone(new_listener.updated_at)
def test_update_with_timeouts(self):
listener = self.create_listener(self.session)
listener_id = listener.id
timeouts = {
'timeout_client_data': 1,
'timeout_member_connect': 2,
'timeout_member_data': 3,
'timeout_tcp_inspect': 4,
}
for item in timeouts:
setattr(listener, item, timeouts[item])
new_listener = self.session.query(
models.Listener).filter_by(id=listener_id).first()
for item in timeouts:
self.assertEqual(timeouts[item], getattr(new_listener, item))
def test_delete(self):
listener = self.create_listener(self.session)
listener_id = listener.id

View File

@ -36,16 +36,14 @@ class HAProxyCompatTestCase(base.TestCase):
"defaults\n"
" log global\n"
" retries 3\n"
" option redispatch\n"
" timeout connect 5000\n"
" timeout client 50000\n"
" timeout server 50000\n\n\n\n"
" option redispatch\n\n\n\n"
"frontend sample_listener_id_1\n"
" option httplog\n"
" maxconn 98\n"
" bind 10.0.0.2:80\n"
" mode http\n"
" default_backend sample_pool_id_1\n\n")
" default_backend sample_pool_id_1\n"
" timeout client 50000\n\n")
self.backend_without_external = (
"backend sample_pool_id_1\n"
" mode http\n"
@ -55,6 +53,9 @@ class HAProxyCompatTestCase(base.TestCase):
" option httpchk GET /index.html\n"
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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 "
@ -67,9 +68,12 @@ class HAProxyCompatTestCase(base.TestCase):
" timeout check 31\n"
" option httpchk GET /index.html\n"
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option external-check\n"
" external-check command /var/lib/octavia/ping-wrapper.sh\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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 "

View File

@ -39,7 +39,8 @@ class TestHaproxyCfg(base.TestCase):
"sample_listener_id_1/FakeCN.pem "
"crt /var/lib/octavia/certs/sample_listener_id_1\n"
" mode http\n"
" default_backend sample_pool_id_1\n\n")
" default_backend sample_pool_id_1\n"
" timeout client 50000\n\n")
be = ("backend sample_pool_id_1\n"
" mode http\n"
" balance roundrobin\n"
@ -49,6 +50,8 @@ class TestHaproxyCfg(base.TestCase):
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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"
@ -77,7 +80,8 @@ class TestHaproxyCfg(base.TestCase):
"ssl crt /var/lib/octavia/certs/"
"sample_listener_id_1/FakeCN.pem\n"
" mode http\n"
" default_backend sample_pool_id_1\n\n")
" default_backend sample_pool_id_1\n"
" timeout client 50000\n\n")
be = ("backend sample_pool_id_1\n"
" mode http\n"
" balance roundrobin\n"
@ -87,6 +91,8 @@ class TestHaproxyCfg(base.TestCase):
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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"
@ -116,6 +122,8 @@ class TestHaproxyCfg(base.TestCase):
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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"
@ -139,6 +147,8 @@ class TestHaproxyCfg(base.TestCase):
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\n"
" server sample_member_id_1 10.0.0.99:82 "
"weight 13 check inter 30s fall 3 rise 2 "
"addr 192.168.1.1 port 9000 "
@ -155,6 +165,72 @@ class TestHaproxyCfg(base.TestCase):
sample_configs.sample_base_expected_config(backend=be),
rendered_obj)
def test_render_template_custom_timeouts(self):
fe = ("frontend sample_listener_id_1\n"
" option httplog\n"
" maxconn 98\n"
" bind 10.0.0.2:80\n"
" mode http\n"
" default_backend sample_pool_id_1\n"
" timeout client 2\n\n")
be = ("backend sample_pool_id_1\n"
" mode http\n"
" balance roundrobin\n"
" cookie SRV insert indirect nocache\n"
" timeout check 31s\n"
" option httpchk GET /index.html\n"
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 1\n"
" timeout server 3\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_amphora_tuple(),
sample_configs.sample_listener_tuple(timeout_member_connect=1,
timeout_client_data=2,
timeout_member_data=3))
self.assertEqual(
sample_configs.sample_base_expected_config(frontend=fe,
backend=be),
rendered_obj)
def test_render_template_null_timeouts(self):
fe = ("frontend sample_listener_id_1\n"
" option httplog\n"
" maxconn 98\n"
" bind 10.0.0.2:80\n"
" mode http\n"
" default_backend sample_pool_id_1\n"
" timeout client 50000\n\n")
be = ("backend sample_pool_id_1\n"
" mode http\n"
" balance roundrobin\n"
" cookie SRV insert indirect nocache\n"
" timeout check 31s\n"
" option httpchk GET /index.html\n"
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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_amphora_tuple(),
sample_configs.sample_listener_tuple(timeout_member_connect=None,
timeout_client_data=None,
timeout_member_data=None))
self.assertEqual(
sample_configs.sample_base_expected_config(frontend=fe,
backend=be),
rendered_obj)
def test_render_template_member_monitor_addr_port(self):
be = ("backend sample_pool_id_1\n"
" mode http\n"
@ -165,6 +241,8 @@ class TestHaproxyCfg(base.TestCase):
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\n"
" server sample_member_id_1 10.0.0.99:82 "
"weight 13 check inter 30s fall 3 rise 2 "
"addr 192.168.1.1 port 9000 "
@ -186,7 +264,8 @@ class TestHaproxyCfg(base.TestCase):
" maxconn 98\n"
" bind 10.0.0.2:443\n"
" mode tcp\n"
" default_backend sample_pool_id_1\n\n")
" default_backend sample_pool_id_1\n"
" timeout client 50000\n\n")
be = ("backend sample_pool_id_1\n"
" mode tcp\n"
" balance roundrobin\n"
@ -196,6 +275,8 @@ class TestHaproxyCfg(base.TestCase):
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\n"
" server sample_member_id_1 10.0.0.99:82 "
"weight 13 check check-ssl verify none inter 30s fall 3 rise 2 "
"cookie sample_member_id_1\n"
@ -214,7 +295,8 @@ class TestHaproxyCfg(base.TestCase):
" maxconn 98\n"
" bind 10.0.0.2:443\n"
" mode tcp\n"
" default_backend sample_pool_id_1\n\n")
" default_backend sample_pool_id_1\n"
" timeout client 50000\n\n")
be = ("backend sample_pool_id_1\n"
" mode tcp\n"
" balance roundrobin\n"
@ -223,6 +305,8 @@ class TestHaproxyCfg(base.TestCase):
" option ssl-hello-chk\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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"
@ -243,6 +327,8 @@ class TestHaproxyCfg(base.TestCase):
" cookie SRV insert indirect nocache\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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 "
@ -263,6 +349,8 @@ class TestHaproxyCfg(base.TestCase):
" external-check command /var/lib/octavia/ping-wrapper.sh\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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"
@ -283,13 +371,16 @@ class TestHaproxyCfg(base.TestCase):
" maxconn 98\n"
" bind 10.0.0.2:443\n"
" mode tcp\n"
" default_backend sample_pool_id_1\n\n")
" default_backend sample_pool_id_1\n"
" timeout client 50000\n\n")
be = ("backend sample_pool_id_1\n"
" mode tcp\n"
" balance roundrobin\n"
" cookie SRV insert indirect nocache\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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 "
@ -306,12 +397,15 @@ class TestHaproxyCfg(base.TestCase):
" maxconn 98\n"
" bind 10.0.0.2:443\n"
" mode tcp\n"
" default_backend sample_pool_id_1\n\n")
" default_backend sample_pool_id_1\n"
" timeout client 50000\n\n")
be = ("backend sample_pool_id_1\n"
" mode tcp\n"
" balance roundrobin\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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(
@ -327,6 +421,8 @@ class TestHaproxyCfg(base.TestCase):
" balance roundrobin\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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(
@ -347,6 +443,8 @@ class TestHaproxyCfg(base.TestCase):
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\n"
" server sample_member_id_1 10.0.0.99:82 "
"weight 13 check inter 30s fall 3 rise 2\n"
" server sample_member_id_2 10.0.0.98:82 "
@ -371,6 +469,8 @@ class TestHaproxyCfg(base.TestCase):
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\n"
" server sample_member_id_1 10.0.0.99:82 "
"weight 13 check inter 30s fall 3 rise 2\n"
" server sample_member_id_2 10.0.0.98:82 "
@ -403,7 +503,8 @@ class TestHaproxyCfg(base.TestCase):
".example.com\n"
" http-request deny if sample_l7rule_id_4 "
"sample_l7rule_id_5\n"
" default_backend sample_pool_id_1\n\n")
" default_backend sample_pool_id_1\n"
" timeout client 50000\n\n")
be = ("backend sample_pool_id_1\n"
" mode http\n"
" balance roundrobin\n"
@ -413,6 +514,8 @@ class TestHaproxyCfg(base.TestCase):
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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 "
@ -427,6 +530,8 @@ class TestHaproxyCfg(base.TestCase):
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\n"
" 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")
rendered_obj = self.jinja_cfg.render_loadbalancer_obj(
@ -446,6 +551,8 @@ class TestHaproxyCfg(base.TestCase):
" option forwardfor\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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"
@ -472,6 +579,8 @@ class TestHaproxyCfg(base.TestCase):
" http-request set-header X-Forwarded-Port %[dst_port]\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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"
@ -495,6 +604,8 @@ class TestHaproxyCfg(base.TestCase):
" timeout check 31s\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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 send-proxy\n"

View File

@ -245,7 +245,12 @@ RET_LISTENER = {
'pools': [RET_POOL_1],
'l7policies': [],
'enabled': True,
'insert_headers': {}}
'insert_headers': {},
'timeout_client_data': 50000,
'timeout_member_connect': 5000,
'timeout_member_data': 50000,
'timeout_tcp_inspect': 0,
}
RET_LISTENER_L7 = {
'id': 'sample_listener_id_1',
@ -261,7 +266,12 @@ RET_LISTENER_L7 = {
'l7policies': [RET_L7POLICY_1, RET_L7POLICY_2, RET_L7POLICY_3,
RET_L7POLICY_4, RET_L7POLICY_5, RET_L7POLICY_6],
'enabled': True,
'insert_headers': {}}
'insert_headers': {},
'timeout_client_data': 50000,
'timeout_member_connect': 5000,
'timeout_member_data': 50000,
'timeout_tcp_inspect': 0,
}
RET_LISTENER_TLS = {
'id': 'sample_listener_id_1',
@ -409,7 +419,11 @@ def sample_listener_tuple(proto=None, monitor=True, persistence=True,
tls=False, sni=False, peer_port=None, topology=None,
l7=False, enabled=True, insert_headers=None,
be_proto=None, monitor_ip_port=False,
monitor_proto=None, backup_member=False):
monitor_proto=None, backup_member=False,
timeout_client_data=50000,
timeout_member_connect=5000,
timeout_member_data=50000,
timeout_tcp_inspect=0):
proto = 'HTTP' if proto is None else proto
if be_proto is None:
be_proto = 'HTTP' if proto is 'TERMINATED_HTTPS' else proto
@ -422,7 +436,9 @@ def sample_listener_tuple(proto=None, monitor=True, persistence=True,
'connection_limit, tls_certificate_id, '
'sni_container_ids, default_tls_container, '
'sni_containers, load_balancer, peer_port, pools, '
'l7policies, enabled, insert_headers',)
'l7policies, enabled, insert_headers, timeout_client_data,'
'timeout_member_connect, timeout_member_data, '
'timeout_tcp_inspect',)
if l7:
pools = [
sample_pool_tuple(
@ -492,7 +508,11 @@ def sample_listener_tuple(proto=None, monitor=True, persistence=True,
pools=pools,
l7policies=l7policies,
enabled=enabled,
insert_headers=insert_headers
insert_headers=insert_headers,
timeout_client_data=timeout_client_data,
timeout_member_connect=timeout_member_connect,
timeout_member_data=timeout_member_data,
timeout_tcp_inspect=timeout_tcp_inspect
)
@ -703,32 +723,41 @@ def sample_l7rule_tuple(id,
def sample_base_expected_config(frontend=None, backend=None,
peers=None, global_opts=None):
peers=None, global_opts=None, defaults=None):
if frontend is None:
frontend = ("frontend sample_listener_id_1\n"
" option httplog\n"
" maxconn 98\n"
" bind 10.0.0.2:80\n"
" mode http\n"
" default_backend sample_pool_id_1\n\n")
" default_backend sample_pool_id_1\n"
" timeout client 50000\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"
" timeout check 31s\n"
" option httpchk GET /index.html\n"
" http-check expect rstatus 418\n"
" fullconn 98\n"
" option allbackups\n"
" timeout connect 5000\n"
" timeout server 50000\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")
"check inter 30s fall 3 rise 2 cookie sample_member_id_2\n"
"\n")
if peers is None:
peers = "\n\n"
if global_opts is None:
global_opts = " maxconn 98\n\n"
if defaults is None:
defaults = ("defaults\n"
" log global\n"
" retries 3\n"
" option redispatch\n\n")
return ("# Configuration for test-lb\n"
"global\n"
" daemon\n"
@ -738,11 +767,4 @@ def sample_base_expected_config(frontend=None, backend=None,
" log /dev/log local1 notice\n"
" stats socket /var/lib/octavia/sample_listener_id_1.sock"
" mode 0666 level user\n" +
global_opts +
"defaults\n"
" log global\n"
" retries 3\n"
" option redispatch\n"
" timeout connect 5000\n"
" timeout client 50000\n"
" timeout server 50000\n\n" + peers + frontend + backend)
global_opts + defaults + peers + frontend + backend)

View File

@ -0,0 +1,11 @@
---
features:
- |
Listeners have four new timeout settings:
* `timeout_client_data`: Frontend client inactivity timeout
* `timeout_member_connect`: Backend member connection timeout
* `timeout_member_data`: Backend member inactivity timeout
* `timeout_tcp_inspect`: Time to wait for TCP packets for content inspection
The value for all of these fields is expected to be in milliseconds.