Add SCTP support in API
Add SCTP support in the API for listeners, pools, health-monitors resources. Story: 2007884 Task: 40255 Change-Id: I57a3c528a20943724bdcd36422c689f496068330
This commit is contained in:
parent
4260d8a74b
commit
639c11751e
@ -760,8 +760,8 @@ healthmonitor-timeout-optional:
|
||||
type: integer
|
||||
healthmonitor-type:
|
||||
description: |
|
||||
The type of health monitor. One of ``HTTP``, ``HTTPS``, ``PING``, ``TCP``,
|
||||
``TLS-HELLO``, or ``UDP-CONNECT``.
|
||||
The type of health monitor. One of ``HTTP``, ``HTTPS``, ``PING``,
|
||||
``SCTP``, ``TCP``, ``TLS-HELLO``, or ``UDP-CONNECT``.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
@ -1228,15 +1228,15 @@ project_id-optional-deprecated:
|
||||
type: string
|
||||
protocol:
|
||||
description: |
|
||||
The protocol for the resource. One of ``HTTP``, ``HTTPS``, ``TCP``,
|
||||
``TERMINATED_HTTPS``, or ``UDP``.
|
||||
The protocol for the resource. One of ``HTTP``, ``HTTPS``, ``SCTP``,
|
||||
``TCP``, ``TERMINATED_HTTPS``, or ``UDP``.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
protocol-pools:
|
||||
description: |
|
||||
The protocol for the resource. One of ``HTTP``, ``HTTPS``, ``PROXY``,
|
||||
``PROXYV2``, ``TCP``, or ``UDP``.
|
||||
``PROXYV2``, ``SCTP``, ``TCP``, or ``UDP``.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
@ -1421,18 +1421,18 @@ session_persistence_cookie:
|
||||
type: string
|
||||
session_persistence_granularity:
|
||||
description: |
|
||||
The netmask used to determine UDP session persistence. Currently only
|
||||
valid for UDP pools with session persistence of SOURCE_IP. Default netmask
|
||||
is 255.255.255.255, meaning per client full IP.
|
||||
The netmask used to determine SCTP or UDP session persistence. Currently
|
||||
only valid for SCTP or UDP pools with session persistence of SOURCE_IP.
|
||||
Default netmask is 255.255.255.255, meaning per client full IP.
|
||||
in: body
|
||||
min_version: 2.2
|
||||
required: false
|
||||
type: string
|
||||
session_persistence_timeout:
|
||||
description: |
|
||||
The timeout, in seconds, after which a UDP flow may be rescheduled to a
|
||||
different member. Currently only applies to UDP pools with session
|
||||
persistence of SOURCE_IP. Default is 360.
|
||||
The timeout, in seconds, after which a SCTP or UDP flow may be rescheduled
|
||||
to a different member. Currently only applies to SCTP or UDP pools with
|
||||
session persistence of SOURCE_IP. Default is 360.
|
||||
in: body
|
||||
min_version: 2.2
|
||||
required: false
|
||||
|
@ -594,20 +594,22 @@ Valid protocol combinations
|
||||
.. |8Y| replace:: |2| |2| |2| |2| Y
|
||||
.. |8N| replace:: |2| |2| |2| |2| N
|
||||
|
||||
+-------------+-------+--------+------+-------------------+------+
|
||||
|| |listener| || HTTP || HTTPS || TCP || TERMINATED_HTTPS || UDP |
|
||||
|| Pool || || || || || |
|
||||
+=============+=======+========+======+===================+======+
|
||||
| HTTP | |2Y| | |2N| | |1Y| | |8Y| | |1N| |
|
||||
+-------------+-------+--------+------+-------------------+------+
|
||||
| HTTPS | |2N| | |2Y| | |1Y| | |8N| | |1N| |
|
||||
+-------------+-------+--------+------+-------------------+------+
|
||||
| PROXY | |2Y| | |2Y| | |1Y| | |8Y| | |1N| |
|
||||
+-------------+-------+--------+------+-------------------+------+
|
||||
| TCP | |2N| | |2Y| | |1Y| | |8N| | |1N| |
|
||||
+-------------+-------+--------+------+-------------------+------+
|
||||
| UDP | |2N| | |2N| | |1N| | |8N| | |1Y| |
|
||||
+-------------+-------+--------+------+-------------------+------+
|
||||
+-------------+-------+--------+-------+------+-------------------+------+
|
||||
|| |listener| || HTTP || HTTPS || SCTP || TCP || TERMINATED_HTTPS || UDP |
|
||||
|| Pool || || || || || || |
|
||||
+=============+=======+========+=======+======+===================+======+
|
||||
| HTTP | |2Y| | |2N| | |2N| | |1Y| | |8Y| | |1N| |
|
||||
+-------------+-------+--------+-------+------+-------------------+------+
|
||||
| HTTPS | |2N| | |2Y| | |2N| | |1Y| | |8N| | |1N| |
|
||||
+-------------+-------+--------+-------+------+-------------------+------+
|
||||
| PROXY | |2Y| | |2Y| | |2N| | |1Y| | |8Y| | |1N| |
|
||||
+-------------+-------+--------+-------+------+-------------------+------+
|
||||
| SCTP | |2N| | |2N| | |2Y| | |1N| | |8N| | |1N| |
|
||||
+-------------+-------+--------+-------+------+-------------------+------+
|
||||
| TCP | |2N| | |2Y| | |2N| | |1Y| | |8N| | |1N| |
|
||||
+-------------+-------+--------+-------+------+-------------------+------+
|
||||
| UDP | |2N| | |2N| | |2N| | |1N| | |8N| | |1Y| |
|
||||
+-------------+-------+--------+-------+------+-------------------+------+
|
||||
|
||||
"Y" means the combination is valid and "N" means invalid.
|
||||
|
||||
@ -640,25 +642,28 @@ Valid protocol combinations
|
||||
.. |5Y| replace:: |2| |2| |1| Y
|
||||
.. |5N| replace:: |2| |2| |1| N
|
||||
|
||||
+-------------------+-------+--------+-------+------+------------+---------------+
|
||||
|| |Health Monitor| || HTTP || HTTPS || PING || TCP || TLS-HELLO || |UDPCONNECT| |
|
||||
|| Pool || || || || || || |
|
||||
+===================+=======+========+=======+======+============+===============+
|
||||
| HTTP | |2Y| | |2Y| | |1Y| | |1Y| | |4Y| | |5N| |
|
||||
+-------------------+-------+--------+-------+------+------------+---------------+
|
||||
| HTTPS | |2Y| | |2Y| | |1Y| | |1Y| | |4Y| | |5N| |
|
||||
+-------------------+-------+--------+-------+------+------------+---------------+
|
||||
| PROXY | |2Y| | |2Y| | |1Y| | |1Y| | |4Y| | |5N| |
|
||||
+-------------------+-------+--------+-------+------+------------+---------------+
|
||||
| TCP | |2Y| | |2Y| | |1Y| | |1Y| | |4Y| | |5N| |
|
||||
+-------------------+-------+--------+-------+------+------------+---------------+
|
||||
| UDP | |2Y| | |2N| | |1N| | |1Y| | |4N| | |5Y| |
|
||||
+-------------------+-------+--------+-------+------+------------+---------------+
|
||||
+-------------------+-------+--------+-------+-------+------+------------+---------------+
|
||||
|| |Health Monitor| || HTTP || HTTPS || PING || SCTP || TCP || TLS-HELLO || |UDPCONNECT| |
|
||||
|| Pool || || || || || || || |
|
||||
+===================+=======+========+=======+=======+======+============+===============+
|
||||
| HTTP | |2Y| | |2Y| | |1Y| | |1N| | |1Y| | |4Y| | |5N| |
|
||||
+-------------------+-------+--------+-------+-------+------+------------+---------------+
|
||||
| HTTPS | |2Y| | |2Y| | |1Y| | |1N| | |1Y| | |4Y| | |5N| |
|
||||
+-------------------+-------+--------+-------+-------+------+------------+---------------+
|
||||
| PROXY | |2Y| | |2Y| | |1Y| | |1N| | |1Y| | |4Y| | |5N| |
|
||||
+-------------------+-------+--------+-------+-------+------+------------+---------------+
|
||||
| SCTP | |2Y| | |2N| | |1N| | |1Y| | |1Y| | |4N| | |5Y| |
|
||||
+-------------------+-------+--------+-------+-------+------+------------+---------------+
|
||||
| TCP | |2Y| | |2Y| | |1Y| | |1N| | |1Y| | |4Y| | |5N| |
|
||||
+-------------------+-------+--------+-------+-------+------+------------+---------------+
|
||||
| UDP | |2Y| | |2N| | |1N| | |1Y| | |1Y| | |4N| | |5Y| |
|
||||
+-------------------+-------+--------+-------+-------+------+------------+---------------+
|
||||
|
||||
"Y" means the combination is valid and "N" means invalid.
|
||||
|
||||
These combinations are mostly as you'd expect for all non-UDP pool protocols:
|
||||
non-UDP pools can have health monitors with any check type besides UDP-CONNECT.
|
||||
For UDP pools however, things are a little more complicated. UDP Pools support
|
||||
UDP-CONNECT but also HTTP and TCP checks. HTTPS checks are technically feasible
|
||||
but have not yet been implemented.
|
||||
These combinations are mostly as you'd expect for all non-UDP/SCTP pool
|
||||
protocols: non-UDP/SCTP pools can have health monitors with any check type
|
||||
besides UDP-CONNECT and SCTP.
|
||||
For UDP or SCTP pools however, things are a little more complicated. UDP and
|
||||
SCTP Pools support UDP-CONNECT and SCTP but also HTTP and TCP checks. HTTPS
|
||||
checks are technically feasible but have not yet been implemented.
|
||||
|
@ -118,7 +118,7 @@ At a minimum, you must specify these health monitor attributes:
|
||||
times out.
|
||||
|
||||
- ``type`` The type of health monitor. One of ``HTTP``, ``HTTPS``, ``PING``,
|
||||
``TCP``, ``TLS-HELLO``, or ``UDP-CONNECT``.
|
||||
``SCTP``, ``TCP``, ``TLS-HELLO``, or ``UDP-CONNECT``.
|
||||
|
||||
Some attributes receive default values if you omit them from the request:
|
||||
|
||||
|
@ -115,7 +115,9 @@ L7 policies with ``action`` of ``REDIRECT_TO_URL`` will return the default HTTP
|
||||
L7 policies with ``action`` of ``REJECT`` will return a ``Forbidden (403)``
|
||||
response code to the requester.
|
||||
|
||||
.. note:: Pools of type ``UDP`` cannot be used in L7 policies at this time.
|
||||
.. note::
|
||||
Pools of type ``SCTP``, ``TCP`` or ``UDP`` cannot be used in L7
|
||||
policies at this time.
|
||||
|
||||
.. rest_status_code:: success ../http-status.yaml
|
||||
|
||||
|
@ -103,7 +103,7 @@ At a minimum, you must specify these pool attributes:
|
||||
|
||||
- ``protocol`` The protocol for which this pool and its members
|
||||
listen. A valid value is ``HTTP``, ``HTTPS``, ``PROXY``, ``PROXYV2``,
|
||||
``TCP``, or ``UDP``.
|
||||
``SCTP``, ``TCP``, or ``UDP``.
|
||||
|
||||
- ``lb_algorithm`` The load-balancer algorithm, such as
|
||||
``ROUND_ROBIN``, ``LEAST_CONNECTIONS``, ``SOURCE_IP`` and ``SOURCE_IP_PORT``,
|
||||
|
@ -1201,7 +1201,7 @@ and validated with the following exceptions:
|
||||
| | | be less than the delay value. |
|
||||
+-----------------------+--------+------------------------------------------+
|
||||
| type | string | The type of health monitor. One of HTTP, |
|
||||
| | | HTTPS, PING, TCP, TLS-HELLO or |
|
||||
| | | HTTPS, PING, SCTP, TCP, TLS-HELLO or |
|
||||
| | | UDP-CONNECT. |
|
||||
+-----------------------+--------+------------------------------------------+
|
||||
| url_path | string | The HTTP URL path of the request sent by |
|
||||
|
@ -159,6 +159,14 @@ cli=openstack loadbalancer healthmonitor create --type UDP-CONNECT <pool>
|
||||
driver.amphora=complete
|
||||
driver.ovn=missing
|
||||
|
||||
[operation.type.SCTP]
|
||||
title=type - SCTP
|
||||
status=optional
|
||||
notes=Use SCTP for the health monitor.
|
||||
cli=openstack loadbalancer healthmonitor create --type SCTP <pool>
|
||||
driver.amphora=missing
|
||||
driver.ovn=missing
|
||||
|
||||
[operation.url_path]
|
||||
title=url_path
|
||||
status=optional
|
||||
|
@ -230,6 +230,14 @@ cli=openstack loadbalancer listener create --protocol UDP <loadbalancer>
|
||||
driver.amphora=complete
|
||||
driver.ovn=complete
|
||||
|
||||
[operation.protocol.SCTP]
|
||||
title=protocol - SCTP
|
||||
status=optional
|
||||
notes=SCTP protocol support for the listener.
|
||||
cli=openstack loadbalancer listener create --protocol SCTP <loadbalancer>
|
||||
driver.amphora=missing
|
||||
driver.ovn=missing
|
||||
|
||||
[operation.protocol_port]
|
||||
title=protocol_port
|
||||
status=mandatory
|
||||
|
@ -138,6 +138,14 @@ cli=openstack loadbalancer pool create --protocol UDP --listener <listener>
|
||||
driver.amphora=complete
|
||||
driver.ovn=complete
|
||||
|
||||
[operation.protocol.SCTP]
|
||||
title=protocol - SCTP
|
||||
status=optional
|
||||
notes=SCTP protocol support for the pool.
|
||||
cli=openstack loadbalancer pool create --protocol SCTP --listener <listener>
|
||||
driver.amphora=missing
|
||||
driver.ovn=missing
|
||||
|
||||
[operation.session_persistence.APP_COOKIE]
|
||||
title=session_persistence - APP_COOKIE
|
||||
status=optional
|
||||
@ -165,7 +173,7 @@ driver.ovn=missing
|
||||
[operation.session_persistence.persistence_timeout]
|
||||
title=session_persistence - persistence_timeout
|
||||
status=optional
|
||||
notes=The timeout, in seconds, after which a UDP flow may be rescheduled to a different member.
|
||||
notes=The timeout, in seconds, after which a SCTP or UDP flow may be rescheduled to a different member.
|
||||
cli=openstack loadbalancer pool create --session-persistence persistence_timeout=360 --listener <listener>
|
||||
driver.amphora=complete
|
||||
driver.ovn=missing
|
||||
@ -173,7 +181,7 @@ driver.ovn=missing
|
||||
[operation.session_persistence.persistence_granularity]
|
||||
title=session_persistence - persistence_granularity
|
||||
status=optional
|
||||
notes=The netmask used to determine UDP SOURCE_IP session persistence.
|
||||
notes=The netmask used to determine SCTP or UDP SOURCE_IP session persistence.
|
||||
cli=openstack loadbalancer pool create --session-persistence persistence_granularity=255.255.255.255 --listener <listener>
|
||||
driver.amphora=complete
|
||||
driver.ovn=missing
|
||||
|
@ -856,8 +856,8 @@ generates the health check in your web application:
|
||||
|
||||
Other health monitors
|
||||
---------------------
|
||||
Other health monitor types include ``PING``, ``TCP``, ``HTTPS``, ``TLS-HELLO``,
|
||||
and ``UDP-CONNECT``.
|
||||
Other health monitor types include ``PING``, ``TCP``, ``HTTPS``, ``SCTP``,
|
||||
``TLS-HELLO``, and ``UDP-CONNECT``.
|
||||
|
||||
``PING`` health monitors send periodic ICMP PING requests to the back-end
|
||||
servers. Obviously, your back-end servers must be configured to allow PINGs in
|
||||
@ -881,6 +881,13 @@ ssl back-end servers. Unfortunately, this causes problems if the servers are
|
||||
performing client certificate validation, as HAProxy won't have a valid cert.
|
||||
In this case, using ``TLS-HELLO`` type monitoring is an alternative.
|
||||
|
||||
``SCTP`` health monitors send an INIT packet to the back-end server's port.
|
||||
If an application is listening on this port, the Operating System should reply
|
||||
with an INIT ACK packet, but if the port is closed, it replies with an ABORT
|
||||
packet.
|
||||
If the health monitor receives an INIT ACK packet, it immediatly closes the
|
||||
connection with an ABORT packet, and considers that the server is ONLINE.
|
||||
|
||||
``TLS-HELLO`` health monitors simply ensure the back-end server responds to
|
||||
SSLv3 client hello messages. It will not check any other health metrics, like
|
||||
status code or body contents.
|
||||
|
@ -131,6 +131,9 @@ class RootController(object):
|
||||
self._add_a_version(versions, 'v2.21', 'v2', 'SUPPORTED',
|
||||
'2020-09-03T00:00:00Z', host_url)
|
||||
# Add PROXYV2 pool protocol
|
||||
self._add_a_version(versions, 'v2.22', 'v2', 'CURRENT',
|
||||
self._add_a_version(versions, 'v2.22', 'v2', 'SUPPORTED',
|
||||
'2020-09-04T00:00:00Z', host_url)
|
||||
# SCTP protocol
|
||||
self._add_a_version(versions, 'v2.23', 'v2', 'CURRENT',
|
||||
'2020-09-07T00:00:00Z', host_url)
|
||||
return {'versions': versions}
|
||||
|
@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
from octavia_lib.api.drivers import data_models as driver_dm
|
||||
from octavia_lib.common import constants as lib_consts
|
||||
from oslo_config import cfg
|
||||
from oslo_db import exception as odb_exceptions
|
||||
from oslo_log import log as logging
|
||||
@ -164,16 +165,19 @@ class HealthMonitorController(base.BaseController):
|
||||
# do not give any information as to what constraint failed
|
||||
raise exceptions.InvalidOption(value='', option='') from e
|
||||
|
||||
def _validate_healthmonitor_request_for_udp(self, request):
|
||||
def _validate_healthmonitor_request_for_udp_sctp(self, request,
|
||||
pool_protocol):
|
||||
if request.type not in (
|
||||
consts.HEALTH_MONITOR_UDP_CONNECT,
|
||||
lib_consts.HEALTH_MONITOR_SCTP,
|
||||
consts.HEALTH_MONITOR_TCP,
|
||||
consts.HEALTH_MONITOR_HTTP):
|
||||
raise exceptions.ValidationException(detail=_(
|
||||
"The associated pool protocol is %(pool_protocol)s, so only "
|
||||
"a %(types)s health monitor is supported.") % {
|
||||
'pool_protocol': consts.PROTOCOL_UDP,
|
||||
'pool_protocol': pool_protocol,
|
||||
'types': '/'.join((consts.HEALTH_MONITOR_UDP_CONNECT,
|
||||
lib_consts.HEALTH_MONITOR_SCTP,
|
||||
consts.HEALTH_MONITOR_TCP,
|
||||
consts.HEALTH_MONITOR_HTTP))})
|
||||
# check the delay value if the HM type is UDP-CONNECT
|
||||
@ -209,14 +213,19 @@ class HealthMonitorController(base.BaseController):
|
||||
raise exceptions.DisabledOption(
|
||||
option='type', value=consts.HEALTH_MONITOR_PING)
|
||||
|
||||
if pool.protocol == consts.PROTOCOL_UDP:
|
||||
self._validate_healthmonitor_request_for_udp(health_monitor)
|
||||
if pool.protocol in (lib_consts.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP):
|
||||
self._validate_healthmonitor_request_for_udp_sctp(health_monitor,
|
||||
pool.protocol)
|
||||
else:
|
||||
if health_monitor.type == consts.HEALTH_MONITOR_UDP_CONNECT:
|
||||
if health_monitor.type in (consts.HEALTH_MONITOR_UDP_CONNECT,
|
||||
lib_consts.HEALTH_MONITOR_SCTP):
|
||||
raise exceptions.ValidationException(detail=_(
|
||||
"The %(type)s type is only supported for pools of type "
|
||||
"%(protocol)s.") % {'type': health_monitor.type,
|
||||
'protocol': consts.PROTOCOL_UDP})
|
||||
"%(protocols)s.") % {
|
||||
'type': health_monitor.type,
|
||||
'protocols': '/'.join((consts.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP))})
|
||||
|
||||
# Load the driver early as it also provides validation
|
||||
driver = driver_factory.get_driver(provider)
|
||||
@ -342,11 +351,12 @@ class HealthMonitorController(base.BaseController):
|
||||
self._auth_validate_action(context, project_id, consts.RBAC_PUT)
|
||||
|
||||
self._validate_update_hm(db_hm, health_monitor)
|
||||
# Validate health monitor update options for UDP-CONNECT type.
|
||||
if (pool.protocol == consts.PROTOCOL_UDP and
|
||||
db_hm.type == consts.HEALTH_MONITOR_UDP_CONNECT):
|
||||
# Validate health monitor update options for UDP/SCTP
|
||||
if pool.protocol in (lib_consts.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP):
|
||||
health_monitor.type = db_hm.type
|
||||
self._validate_healthmonitor_request_for_udp(health_monitor)
|
||||
self._validate_healthmonitor_request_for_udp_sctp(health_monitor,
|
||||
pool.protocol)
|
||||
|
||||
self._set_default_on_none(health_monitor)
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
from octavia_lib.api.drivers import data_models as driver_dm
|
||||
from octavia_lib.common import constants as lib_consts
|
||||
from oslo_config import cfg
|
||||
from oslo_db import exception as odb_exceptions
|
||||
from oslo_log import log as logging
|
||||
@ -175,12 +176,13 @@ class ListenersController(base.BaseController):
|
||||
self._validate_insert_headers(
|
||||
listener_dict['insert_headers'].keys(), listener_protocol)
|
||||
|
||||
# Check for UDP compatibility
|
||||
if (listener_protocol == constants.PROTOCOL_UDP and
|
||||
# Check for UDP/SCTP compatibility
|
||||
if (listener_protocol in (constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP) and
|
||||
self._is_tls_or_insert_header(listener_dict)):
|
||||
raise exceptions.ValidationException(
|
||||
detail=_("%s protocol listener does not "
|
||||
"support TLS.") % constants.PROTOCOL_UDP)
|
||||
"support TLS.") % listener_protocol)
|
||||
|
||||
# Check for TLS disabled
|
||||
if (not CONF.api_settings.allow_tls_terminated_listeners and
|
||||
@ -251,8 +253,8 @@ class ListenersController(base.BaseController):
|
||||
listener_dict.get('client_ca_tls_certificate_id'),
|
||||
listener_dict.get('client_crl_container_id', None))
|
||||
|
||||
# Validate that the L4 protocol (UDP or TCP) is not already used for
|
||||
# the specified protocol_port in this load balancer
|
||||
# Validate that the L4 protocol (UDP, TCP or SCTP) is not already used
|
||||
# for the specified protocol_port in this load balancer
|
||||
pcontext = pecan_request.context
|
||||
query_filter = {
|
||||
'project_id': listener_dict['project_id'],
|
||||
@ -435,12 +437,13 @@ class ListenersController(base.BaseController):
|
||||
raise exceptions.ValidationException(
|
||||
detail='No listener object supplied.')
|
||||
|
||||
# Check for UDP compatibility
|
||||
if (db_listener.protocol == constants.PROTOCOL_UDP and
|
||||
# Check for UDP/SCTP compatibility
|
||||
if (db_listener.protocol in (constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP) and
|
||||
self._is_tls_or_insert_header(listener.to_dict())):
|
||||
raise exceptions.ValidationException(detail=_(
|
||||
"%s protocol listener does not support TLS or header "
|
||||
"insertion.") % constants.PROTOCOL_UDP)
|
||||
"insertion.") % db_listener.protocol)
|
||||
|
||||
# Check for certs when not TERMINATED_HTTPS
|
||||
if (db_listener.protocol != constants.PROTOCOL_TERMINATED_HTTPS and
|
||||
|
@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
from octavia_lib.api.drivers import data_models as driver_dm
|
||||
from octavia_lib.common import constants as lib_consts
|
||||
from oslo_config import cfg
|
||||
from oslo_db import exception as odb_exceptions
|
||||
from oslo_log import log as logging
|
||||
@ -165,7 +166,7 @@ class PoolsController(base.BaseController):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _validate_pool_request_for_udp(self, request):
|
||||
def _validate_pool_request_for_udp_sctp(self, request):
|
||||
if request.session_persistence:
|
||||
if (request.session_persistence.type ==
|
||||
constants.SESSION_PERSISTENCE_SOURCE_IP and
|
||||
@ -174,14 +175,15 @@ class PoolsController(base.BaseController):
|
||||
check_exist_attrs=['type', 'persistence_timeout',
|
||||
'persistence_granularity'])):
|
||||
raise exceptions.ValidationException(detail=_(
|
||||
"session_persistence %s type for UDP protocol "
|
||||
"session_persistence %s type for UDP and SCTP protocols "
|
||||
"only accepts: type, persistence_timeout, "
|
||||
"persistence_granularity.") % (
|
||||
constants.SESSION_PERSISTENCE_SOURCE_IP))
|
||||
if request.session_persistence.cookie_name:
|
||||
raise exceptions.ValidationException(detail=_(
|
||||
"Cookie names are not supported for %s pools.") %
|
||||
constants.PROTOCOL_UDP)
|
||||
"/".join((constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP)))
|
||||
if request.session_persistence.type in [
|
||||
constants.SESSION_PERSISTENCE_HTTP_COOKIE,
|
||||
constants.SESSION_PERSISTENCE_APP_COOKIE]:
|
||||
@ -189,7 +191,8 @@ class PoolsController(base.BaseController):
|
||||
"Session persistence of type %(type)s is not supported "
|
||||
"for %(protocol)s protocol pools.") % {
|
||||
'type': request.session_persistence.type,
|
||||
'protocol': constants.PROTOCOL_UDP})
|
||||
'protocol': "/".join((constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP))})
|
||||
|
||||
@wsme_pecan.wsexpose(pool_types.PoolRootResponse,
|
||||
body=pool_types.PoolRootPOST, status_code=201)
|
||||
@ -226,15 +229,16 @@ class PoolsController(base.BaseController):
|
||||
if pool.listener_id and listener:
|
||||
self._validate_protocol(listener.protocol, pool.protocol)
|
||||
|
||||
if pool.protocol == constants.PROTOCOL_UDP:
|
||||
self._validate_pool_request_for_udp(pool)
|
||||
if pool.protocol in (constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP):
|
||||
self._validate_pool_request_for_udp_sctp(pool)
|
||||
else:
|
||||
if (pool.session_persistence and (
|
||||
pool.session_persistence.persistence_timeout or
|
||||
pool.session_persistence.persistence_granularity)):
|
||||
raise exceptions.ValidationException(detail=_(
|
||||
"persistence_timeout and persistence_granularity "
|
||||
"is only for UDP protocol pools."))
|
||||
"is only for UDP and SCTP protocol pools."))
|
||||
|
||||
if pool.session_persistence:
|
||||
sp_dict = pool.session_persistence.to_dict(render_unsets=False)
|
||||
@ -311,16 +315,20 @@ class PoolsController(base.BaseController):
|
||||
hm[constants.PROJECT_ID] = db_pool.project_id
|
||||
new_hm = health_monitor.HealthMonitorController()._graph_create(
|
||||
lock_session, hm)
|
||||
if db_pool.protocol == constants.PROTOCOL_UDP:
|
||||
if db_pool.protocol in (constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP):
|
||||
health_monitor.HealthMonitorController(
|
||||
)._validate_healthmonitor_request_for_udp(new_hm)
|
||||
)._validate_healthmonitor_request_for_udp_sctp(new_hm,
|
||||
db_pool)
|
||||
else:
|
||||
if new_hm.type == constants.HEALTH_MONITOR_UDP_CONNECT:
|
||||
if new_hm.type in (constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
lib_consts.HEALTH_MONITOR_SCTP):
|
||||
raise exceptions.ValidationException(detail=_(
|
||||
"The %(type)s type is only supported for pools of "
|
||||
"type %(protocol)s.") % {
|
||||
'type': new_hm.type,
|
||||
'protocol': constants.PROTOCOL_UDP})
|
||||
'protocol': '/'.join((constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP))})
|
||||
db_pool.health_monitor = new_hm
|
||||
|
||||
# Now check quotas for members
|
||||
@ -344,8 +352,9 @@ class PoolsController(base.BaseController):
|
||||
|
||||
def _validate_pool_PUT(self, pool, db_pool):
|
||||
|
||||
if db_pool.protocol == constants.PROTOCOL_UDP:
|
||||
self._validate_pool_request_for_udp(pool)
|
||||
if db_pool.protocol in (constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP):
|
||||
self._validate_pool_request_for_udp_sctp(pool)
|
||||
else:
|
||||
if (pool.session_persistence and (
|
||||
pool.session_persistence.persistence_timeout or
|
||||
|
@ -214,7 +214,8 @@ VALID_LISTENER_POOL_PROTOCOL_MAP = {
|
||||
lib_consts.PROTOCOL_PROXYV2, PROTOCOL_TCP],
|
||||
PROTOCOL_TERMINATED_HTTPS: [PROTOCOL_HTTP, PROTOCOL_PROXY,
|
||||
lib_consts.PROTOCOL_PROXYV2],
|
||||
PROTOCOL_UDP: [PROTOCOL_UDP]}
|
||||
PROTOCOL_UDP: [PROTOCOL_UDP],
|
||||
lib_consts.PROTOCOL_SCTP: [lib_consts.PROTOCOL_SCTP]}
|
||||
|
||||
# API Integer Ranges
|
||||
MIN_PORT_NUMBER = 1
|
||||
@ -815,6 +816,7 @@ L4_PROTOCOL_MAP = {
|
||||
PROTOCOL_PROXY: PROTOCOL_TCP,
|
||||
lib_consts.PROTOCOL_PROXYV2: PROTOCOL_TCP,
|
||||
PROTOCOL_UDP: PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP: lib_consts.PROTOCOL_SCTP,
|
||||
}
|
||||
|
||||
# Image drivers
|
||||
|
@ -0,0 +1,46 @@
|
||||
# Copyright 2020 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""sctp support
|
||||
|
||||
Revision ID: 8b47b2546312
|
||||
Revises: e6ee84f0abf3
|
||||
Create Date: 2020-06-26 09:26:45.397873
|
||||
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import sql
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '8b47b2546312'
|
||||
down_revision = 'e6ee84f0abf3'
|
||||
|
||||
|
||||
def upgrade():
|
||||
for table in ['protocol', 'health_monitor_type']:
|
||||
insert_table = sql.table(
|
||||
table,
|
||||
sql.column(u'name', sa.String),
|
||||
sql.column(u'description', sa.String)
|
||||
)
|
||||
|
||||
op.bulk_insert(
|
||||
insert_table,
|
||||
[
|
||||
{'name': 'SCTP'}
|
||||
]
|
||||
)
|
@ -16,6 +16,7 @@ import time
|
||||
|
||||
from neutronclient.common import exceptions as neutron_client_exceptions
|
||||
from novaclient import exceptions as nova_client_exceptions
|
||||
from octavia_lib.common import constants as lib_consts
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from stevedore import driver as stevedore_driver
|
||||
@ -159,6 +160,8 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
||||
protocol = constants.PROTOCOL_TCP.lower()
|
||||
if listener.protocol == constants.PROTOCOL_UDP:
|
||||
protocol = constants.PROTOCOL_UDP.lower()
|
||||
elif listener.protocol == lib_consts.PROTOCOL_SCTP:
|
||||
protocol = lib_consts.PROTOCOL_SCTP.lower()
|
||||
|
||||
if listener.allowed_cidrs:
|
||||
for ac in listener.allowed_cidrs:
|
||||
@ -183,7 +186,8 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
||||
# None ports with the egress rules. VRRP uses protocol 51 and 112
|
||||
if (rule.get('direction') == 'egress' or
|
||||
rule.get('protocol').upper() not in
|
||||
[constants.PROTOCOL_TCP, constants.PROTOCOL_UDP]):
|
||||
[constants.PROTOCOL_TCP, constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP]):
|
||||
continue
|
||||
old_ports.append((rule.get('port_range_max'),
|
||||
rule.get('protocol').lower(),
|
||||
|
@ -45,7 +45,7 @@ class TestRootController(base_db_test.OctaviaDBTestBase):
|
||||
def test_api_versions(self):
|
||||
versions = self._get_versions_with_config()
|
||||
version_ids = tuple(v.get('id') for v in versions)
|
||||
self.assertEqual(23, len(version_ids))
|
||||
self.assertEqual(24, len(version_ids))
|
||||
self.assertIn('v2.0', version_ids)
|
||||
self.assertIn('v2.1', version_ids)
|
||||
self.assertIn('v2.2', version_ids)
|
||||
@ -69,6 +69,7 @@ class TestRootController(base_db_test.OctaviaDBTestBase):
|
||||
self.assertIn('v2.20', version_ids)
|
||||
self.assertIn('v2.21', version_ids)
|
||||
self.assertIn('v2.22', version_ids)
|
||||
self.assertIn('v2.23', version_ids)
|
||||
|
||||
# Each version should have a 'self' 'href' to the API version URL
|
||||
# [{u'rel': u'self', u'href': u'http://localhost/v2'}]
|
||||
|
@ -24,6 +24,7 @@ from octavia.common import data_models
|
||||
from octavia.common import exceptions
|
||||
from octavia.db import repositories
|
||||
from octavia.tests.functional.api.v2 import base
|
||||
from octavia_lib.common import constants as lib_consts
|
||||
|
||||
|
||||
class TestHealthMonitor(base.BaseAPITest):
|
||||
@ -56,6 +57,7 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||
self.set_lb_status(self.lb_id)
|
||||
self.pool_repo = repositories.PoolRepository()
|
||||
self._setup_udp_lb_resources()
|
||||
self._setup_sctp_lb_resources()
|
||||
|
||||
def _setup_udp_lb_resources(self):
|
||||
self.udp_lb = self.create_load_balancer(uuidutils.generate_uuid()).get(
|
||||
@ -80,6 +82,25 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||
group='api_settings',
|
||||
udp_connect_min_interval_health_monitor='3')
|
||||
|
||||
def _setup_sctp_lb_resources(self):
|
||||
self.sctp_lb = self.create_load_balancer(
|
||||
uuidutils.generate_uuid()).get('loadbalancer')
|
||||
self.sctp_lb_id = self.sctp_lb.get('id')
|
||||
self.set_lb_status(self.sctp_lb_id)
|
||||
|
||||
self.sctp_listener = self.create_listener(
|
||||
lib_consts.PROTOCOL_SCTP, 8888,
|
||||
self.sctp_lb_id).get('listener')
|
||||
self.sctp_listener_id = self.sctp_listener.get('id')
|
||||
self.set_lb_status(self.sctp_lb_id)
|
||||
|
||||
self.sctp_pool_with_listener = self.create_pool(
|
||||
None, lib_consts.PROTOCOL_SCTP, constants.LB_ALGORITHM_ROUND_ROBIN,
|
||||
listener_id=self.sctp_listener_id)
|
||||
self.sctp_pool_with_listener_id = (
|
||||
self.sctp_pool_with_listener.get('pool').get('id'))
|
||||
self.set_lb_status(self.sctp_lb_id)
|
||||
|
||||
def test_get(self):
|
||||
api_hm = self.create_health_monitor(
|
||||
self.pool_id, constants.HEALTH_MONITOR_HTTP,
|
||||
@ -936,6 +957,32 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||
self.assertEqual('/test.html', api_hm.get('url_path'))
|
||||
self.assertEqual('200-201', api_hm.get('expected_codes'))
|
||||
|
||||
def test_create_udp_case_with_sctp_type(self):
|
||||
# create with SCTP type
|
||||
api_hm = self.create_health_monitor(
|
||||
self.udp_pool_with_listener_id,
|
||||
lib_consts.HEALTH_MONITOR_SCTP,
|
||||
3, 1, 1, 1).get(self.root_tag)
|
||||
self.assert_correct_status(
|
||||
lb_id=self.udp_lb_id, listener_id=self.udp_listener_id,
|
||||
pool_id=self.udp_pool_with_listener_id, hm_id=api_hm.get('id'),
|
||||
lb_prov_status=constants.PENDING_UPDATE,
|
||||
listener_prov_status=constants.PENDING_UPDATE,
|
||||
pool_prov_status=constants.PENDING_UPDATE,
|
||||
hm_prov_status=constants.PENDING_CREATE,
|
||||
hm_op_status=constants.OFFLINE)
|
||||
self.set_lb_status(self.udp_lb_id)
|
||||
self.assertEqual(lib_consts.HEALTH_MONITOR_SCTP,
|
||||
api_hm.get('type'))
|
||||
self.assertEqual(3, api_hm.get('delay'))
|
||||
self.assertEqual(1, api_hm.get('timeout'))
|
||||
self.assertEqual(1, api_hm.get('max_retries_down'))
|
||||
self.assertEqual(1, api_hm.get('max_retries'))
|
||||
# Verify the L7 fields is None
|
||||
self.assertIsNone(api_hm.get('http_method'))
|
||||
self.assertIsNone(api_hm.get('url_path'))
|
||||
self.assertIsNone(api_hm.get('expected_codes'))
|
||||
|
||||
def test_udp_case_when_udp_connect_min_interval_health_monitor_set(self):
|
||||
# negative case first
|
||||
req_dict = {'pool_id': self.udp_pool_with_listener_id,
|
||||
@ -981,6 +1028,7 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||
"monitor is supported.") % {
|
||||
'pool_protocol': constants.PROTOCOL_UDP,
|
||||
'types': '/'.join([constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
lib_consts.HEALTH_MONITOR_SCTP,
|
||||
constants.HEALTH_MONITOR_TCP,
|
||||
constants.HEALTH_MONITOR_HTTP])}
|
||||
|
||||
@ -1005,7 +1053,8 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||
"supported for pools of type "
|
||||
"%(protocol)s.") % {
|
||||
'type': constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
'protocol': constants.PROTOCOL_UDP}
|
||||
'protocol': '/'.join((constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP))}
|
||||
res = self.post(self.HMS_PATH, self._build_body(req_dict),
|
||||
status=400,
|
||||
expect_errors=True)
|
||||
@ -1014,6 +1063,108 @@ class TestHealthMonitor(base.BaseAPITest):
|
||||
lb_id=self.udp_lb_id, listener_id=self.udp_listener_id,
|
||||
pool_id=self.udp_pool_with_listener_id)
|
||||
|
||||
def test_create_sctp_case_with_udp_connect_type(self):
|
||||
# create with UDP-CONNECT type
|
||||
api_hm = self.create_health_monitor(
|
||||
self.sctp_pool_with_listener_id,
|
||||
constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
3, 1, 1, 1).get(self.root_tag)
|
||||
self.assert_correct_status(
|
||||
lb_id=self.sctp_lb_id, listener_id=self.sctp_listener_id,
|
||||
pool_id=self.sctp_pool_with_listener_id, hm_id=api_hm.get('id'),
|
||||
lb_prov_status=constants.PENDING_UPDATE,
|
||||
listener_prov_status=constants.PENDING_UPDATE,
|
||||
pool_prov_status=constants.PENDING_UPDATE,
|
||||
hm_prov_status=constants.PENDING_CREATE,
|
||||
hm_op_status=constants.OFFLINE)
|
||||
self.set_lb_status(self.sctp_lb_id)
|
||||
self.assertEqual(constants.HEALTH_MONITOR_UDP_CONNECT,
|
||||
api_hm.get('type'))
|
||||
self.assertEqual(3, api_hm.get('delay'))
|
||||
self.assertEqual(1, api_hm.get('timeout'))
|
||||
self.assertEqual(1, api_hm.get('max_retries_down'))
|
||||
self.assertEqual(1, api_hm.get('max_retries'))
|
||||
# Verify the L7 fields is None
|
||||
self.assertIsNone(api_hm.get('http_method'))
|
||||
self.assertIsNone(api_hm.get('url_path'))
|
||||
self.assertIsNone(api_hm.get('expected_codes'))
|
||||
|
||||
def test_create_sctp_case_with_tcp_type(self):
|
||||
# create with TCP type
|
||||
api_hm = self.create_health_monitor(
|
||||
self.sctp_pool_with_listener_id, constants.HEALTH_MONITOR_TCP,
|
||||
3, 1, 1, 1).get(self.root_tag)
|
||||
self.assert_correct_status(
|
||||
lb_id=self.sctp_lb_id, listener_id=self.sctp_listener_id,
|
||||
pool_id=self.sctp_pool_with_listener_id, hm_id=api_hm.get('id'),
|
||||
lb_prov_status=constants.PENDING_UPDATE,
|
||||
listener_prov_status=constants.PENDING_UPDATE,
|
||||
pool_prov_status=constants.PENDING_UPDATE,
|
||||
hm_prov_status=constants.PENDING_CREATE,
|
||||
hm_op_status=constants.OFFLINE)
|
||||
self.set_lb_status(self.sctp_lb_id)
|
||||
self.assertEqual(constants.HEALTH_MONITOR_TCP, api_hm.get('type'))
|
||||
self.assertEqual(3, api_hm.get('delay'))
|
||||
self.assertEqual(1, api_hm.get('timeout'))
|
||||
self.assertEqual(1, api_hm.get('max_retries_down'))
|
||||
self.assertEqual(1, api_hm.get('max_retries'))
|
||||
self.assertIsNone(api_hm.get('http_method'))
|
||||
self.assertIsNone(api_hm.get('url_path'))
|
||||
self.assertIsNone(api_hm.get('expected_codes'))
|
||||
|
||||
def test_create_sctp_case_with_http_type(self):
|
||||
# create with HTTP type
|
||||
api_hm = self.create_health_monitor(
|
||||
self.sctp_pool_with_listener_id, constants.HEALTH_MONITOR_HTTP,
|
||||
3, 1, 1, 1, url_path='/test.html',
|
||||
http_method=constants.HEALTH_MONITOR_HTTP_METHOD_GET,
|
||||
expected_codes='200-201').get(self.root_tag)
|
||||
self.assert_correct_status(
|
||||
lb_id=self.sctp_lb_id, listener_id=self.sctp_listener_id,
|
||||
pool_id=self.sctp_pool_with_listener_id, hm_id=api_hm.get('id'),
|
||||
lb_prov_status=constants.PENDING_UPDATE,
|
||||
listener_prov_status=constants.PENDING_UPDATE,
|
||||
pool_prov_status=constants.PENDING_UPDATE,
|
||||
hm_prov_status=constants.PENDING_CREATE,
|
||||
hm_op_status=constants.OFFLINE)
|
||||
self.set_lb_status(self.sctp_lb_id)
|
||||
self.assertEqual(constants.HEALTH_MONITOR_HTTP, api_hm.get('type'))
|
||||
self.assertEqual(3, api_hm.get('delay'))
|
||||
self.assertEqual(1, api_hm.get('timeout'))
|
||||
self.assertEqual(1, api_hm.get('max_retries_down'))
|
||||
self.assertEqual(1, api_hm.get('max_retries'))
|
||||
self.assertEqual(3, api_hm.get('delay'))
|
||||
self.assertEqual(constants.HEALTH_MONITOR_HTTP_METHOD_GET,
|
||||
api_hm.get('http_method'))
|
||||
self.assertEqual('/test.html', api_hm.get('url_path'))
|
||||
self.assertEqual('200-201', api_hm.get('expected_codes'))
|
||||
|
||||
def test_create_sctp_case_with_sctp_type(self):
|
||||
# create with SCTP type
|
||||
api_hm = self.create_health_monitor(
|
||||
self.sctp_pool_with_listener_id,
|
||||
lib_consts.HEALTH_MONITOR_SCTP,
|
||||
3, 1, 1, 1).get(self.root_tag)
|
||||
self.assert_correct_status(
|
||||
lb_id=self.sctp_lb_id, listener_id=self.sctp_listener_id,
|
||||
pool_id=self.sctp_pool_with_listener_id, hm_id=api_hm.get('id'),
|
||||
lb_prov_status=constants.PENDING_UPDATE,
|
||||
listener_prov_status=constants.PENDING_UPDATE,
|
||||
pool_prov_status=constants.PENDING_UPDATE,
|
||||
hm_prov_status=constants.PENDING_CREATE,
|
||||
hm_op_status=constants.OFFLINE)
|
||||
self.set_lb_status(self.sctp_lb_id)
|
||||
self.assertEqual(lib_consts.HEALTH_MONITOR_SCTP,
|
||||
api_hm.get('type'))
|
||||
self.assertEqual(3, api_hm.get('delay'))
|
||||
self.assertEqual(1, api_hm.get('timeout'))
|
||||
self.assertEqual(1, api_hm.get('max_retries_down'))
|
||||
self.assertEqual(1, api_hm.get('max_retries'))
|
||||
# Verify the L7 fields is None
|
||||
self.assertIsNone(api_hm.get('http_method'))
|
||||
self.assertIsNone(api_hm.get('url_path'))
|
||||
self.assertIsNone(api_hm.get('expected_codes'))
|
||||
|
||||
def test_ensure_L7_fields_filled_during_create(self):
|
||||
# Create a health monitor with a load balancer pool
|
||||
api_hm = self.create_health_monitor(
|
||||
|
@ -27,6 +27,7 @@ from octavia.db import api as db_api
|
||||
from octavia.tests.common import constants as c_const
|
||||
from octavia.tests.common import sample_certs
|
||||
from octavia.tests.functional.api.v2 import base
|
||||
from octavia_lib.common import constants as lib_consts
|
||||
|
||||
|
||||
class TestPool(base.BaseAPITest):
|
||||
@ -1026,7 +1027,9 @@ class TestPool(base.BaseAPITest):
|
||||
'lb_algorithm': constants.LB_ALGORITHM_ROUND_ROBIN,
|
||||
'session_persistence': sp}
|
||||
expect_error_msg = ("Validation failure: Cookie names are not "
|
||||
"supported for %s pools.") % constants.PROTOCOL_UDP
|
||||
"supported for %s pools.") % (
|
||||
"/".join((constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP)))
|
||||
res = self.post(self.POOLS_PATH, self._build_body(req_dict),
|
||||
status=400, expect_errors=True)
|
||||
self.assertEqual(expect_error_msg, res.json['faultstring'])
|
||||
@ -1047,7 +1050,10 @@ class TestPool(base.BaseAPITest):
|
||||
constants.SESSION_PERSISTENCE_APP_COOKIE]:
|
||||
expect_error_msg = ("Validation failure: Session persistence of "
|
||||
"type %s is not supported for %s protocol "
|
||||
"pools.") % (type, constants.PROTOCOL_UDP)
|
||||
"pools.") % (
|
||||
type,
|
||||
"/".join((constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP)))
|
||||
sp.update({'type': type})
|
||||
req_dict['session_persistence'] = sp
|
||||
res = self.post(self.POOLS_PATH, self._build_body(req_dict),
|
||||
@ -1070,9 +1076,11 @@ class TestPool(base.BaseAPITest):
|
||||
'session_persistence': sp}
|
||||
expect_error_msg = (
|
||||
"Validation failure: session_persistence %s type for %s "
|
||||
"protocol only accepts: type, persistence_timeout, "
|
||||
"protocols only accepts: type, persistence_timeout, "
|
||||
"persistence_granularity.") % (
|
||||
constants.SESSION_PERSISTENCE_SOURCE_IP, constants.PROTOCOL_UDP)
|
||||
constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||
" and ".join((constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP)))
|
||||
res = self.post(self.POOLS_PATH, self._build_body(req_dict),
|
||||
status=400, expect_errors=True)
|
||||
self.assertEqual(expect_error_msg, res.json['faultstring'])
|
||||
@ -1092,7 +1100,9 @@ class TestPool(base.BaseAPITest):
|
||||
'lb_algorithm': constants.LB_ALGORITHM_ROUND_ROBIN}
|
||||
expect_error_msg = ("Validation failure: persistence_timeout and "
|
||||
"persistence_granularity is only for %s protocol "
|
||||
"pools.") % constants.PROTOCOL_UDP
|
||||
"pools.") % (
|
||||
" and ".join((constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP)))
|
||||
for s in sps:
|
||||
req_dict.update({'session_persistence': s})
|
||||
res = self.post(self.POOLS_PATH, self._build_body(req_dict),
|
||||
@ -1320,7 +1330,8 @@ class TestPool(base.BaseAPITest):
|
||||
# Error during update pool with non-UDP type and cookie_name.
|
||||
expect_error_msg = (
|
||||
"Validation failure: Cookie names are not supported for %s"
|
||||
" pools.") % constants.PROTOCOL_UDP
|
||||
" pools.") % ("/".join((constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP)))
|
||||
sess_p['type'] = constants.SESSION_PERSISTENCE_HTTP_COOKIE
|
||||
sess_p['cookie_name'] = 'test-cookie-name'
|
||||
new_pool = {'session_persistence': sess_p}
|
||||
@ -1333,10 +1344,11 @@ class TestPool(base.BaseAPITest):
|
||||
|
||||
# Error during update pool with source ip type and more options.
|
||||
expect_error_msg = (
|
||||
"Validation failure: session_persistence %s type for %s protocol "
|
||||
"Validation failure: session_persistence %s type for %s protocols "
|
||||
"only accepts: type, persistence_timeout, "
|
||||
"persistence_granularity.") % (
|
||||
constants.SESSION_PERSISTENCE_SOURCE_IP, constants.PROTOCOL_UDP)
|
||||
constants.SESSION_PERSISTENCE_SOURCE_IP,
|
||||
" and ".join((constants.PROTOCOL_UDP, lib_consts.PROTOCOL_SCTP)))
|
||||
sess_p['type'] = constants.SESSION_PERSISTENCE_SOURCE_IP
|
||||
sess_p['cookie_name'] = 'test-cookie-name'
|
||||
sess_p['persistence_timeout'] = 4
|
||||
@ -1354,7 +1366,10 @@ class TestPool(base.BaseAPITest):
|
||||
constants.SESSION_PERSISTENCE_HTTP_COOKIE]:
|
||||
expect_error_msg = ("Validation failure: Session persistence of "
|
||||
"type %s is not supported for %s protocol "
|
||||
"pools.") % (ty, constants.PROTOCOL_UDP)
|
||||
"pools.") % (
|
||||
ty,
|
||||
"/".join((constants.PROTOCOL_UDP,
|
||||
lib_consts.PROTOCOL_SCTP)))
|
||||
sess_p['type'] = ty
|
||||
res = self.put(self.POOL_PATH.format(pool_id=api_pool.get('id')),
|
||||
self._build_body(new_pool), status=400,
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add support for SCTP protocol. SCTP support has been added in the Octavia
|
||||
API for listener, pool, and health-monitor resources.
|
Loading…
Reference in New Issue
Block a user