Support L7policy redirect http code

Currently, L7Policy already support the redirection by url_prefix.
Then we can support the redirection with HTTP code.

This patch adds an new option 'redirect_http_code' to L7Policy API.

Story: 2003609
Task: 24941
Change-Id: Id0c9c376ffbc2fb10ddb988537d0ef1a8205e586
This commit is contained in:
ZhaoBo 2018-12-13 10:10:38 +08:00 committed by Michael Johnson
parent 24e80ba44c
commit 25fb7e4c32
29 changed files with 305 additions and 29 deletions

View File

@ -704,6 +704,26 @@ l7policy-position-optional:
in: body
required: false
type: integer
l7policy-redirect-http-code:
description: |
Requests matching this policy will be redirected to the specified URL or
Prefix URL with the HTTP response code. Valid if ``action`` is
``REDIRECT_TO_URL`` or ``REDIRECT_PREFIX``. Valid options are: 301, 302,
303, 307, or 308. Default is 302.
in: body
min_version: 2.9
required: true
type: integer
l7policy-redirect-http-code-optional:
description: |
Requests matching this policy will be redirected to the specified URL or
Prefix URL with the HTTP response code. Valid if ``action`` is
``REDIRECT_TO_URL`` or ``REDIRECT_PREFIX``. Valid options are: 301, 302,
303, 307, or 308. Default is 302.
in: body
min_version: 2.9
required: false
type: integer
l7policy-redirect-pool_id:
description: |
Requests matching this policy will be redirected to the pool with this ID.

View File

@ -12,6 +12,7 @@
"created_at": "2017-06-24T23:25:14",
"provisioning_status": "ACTIVE",
"updated_at": "2017-06-24T23:30:05",
"redirect_http_code": 302,
"redirect_pool_id": null,
"redirect_prefix": null,
"redirect_url": "http://www.example.com",

View File

@ -1 +1 @@
curl -X POST -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"l7policy":{"description":"Redirect requests to example.com","admin_state_up":true,"listener_id":"023f2e34-7806-443b-bfae-16c324569a3d","redirect_url":"http://www.example.com","name":"redirect-example.com","action":"REDIRECT_TO_URL","position":1,"tags":["test_tag"]}}' http://198.51.100.10:9876/v2/lbaas/l7policies
curl -X POST -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"l7policy":{"description":"Redirect requests to example.com","admin_state_up":true,"listener_id":"023f2e34-7806-443b-bfae-16c324569a3d","redirect_http_code":301,"redirect_url":"http://www.example.com","name":"redirect-example.com","action":"REDIRECT_TO_URL","position":1,"tags":["test_tag"]}}' http://198.51.100.10:9876/v2/lbaas/l7policies

View File

@ -4,6 +4,7 @@
"admin_state_up": true,
"listener_id": "023f2e34-7806-443b-bfae-16c324569a3d",
"redirect_url": "http://www.example.com",
"redirect_http_code": 301,
"name": "redirect-example.com",
"action": "REDIRECT_TO_URL",
"position": 1,

View File

@ -12,6 +12,7 @@
"created_at": "2017-06-24T23:25:14",
"provisioning_status": "PENDING_CREATE",
"updated_at": "2017-06-24T23:30:05",
"redirect_http_code": 301,
"redirect_pool_id": null,
"redirect_prefix": null,
"redirect_url": "http://www.example.com",

View File

@ -12,6 +12,7 @@
"created_at": "2017-06-24T23:25:14",
"provisioning_status": "ACTIVE",
"updated_at": "2017-06-24T23:30:05",
"redirect_http_code": 302,
"redirect_pool_id": null,
"redirect_prefix": null,
"redirect_url": "http://www.example.com",

View File

@ -1 +1 @@
curl -X PUT -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"l7policy":{"description":"Redirect requests to images.example.com","admin_state_up":true,"redirect_url":"http://images.example.com","name":"redirect-images.example.com","action":"REDIRECT_TO_URL","position":1,"tags":["updated_tag"]}}' http://198.51.100.10:9876/v2/lbaas/l7policies/8a1412f0-4c32-4257-8b07-af4770b604fd
curl -X PUT -H "Content-Type: application/json" -H "X-Auth-Token: <token>" -d '{"l7policy":{"description":"Redirect requests to images.example.com","admin_state_up":true,"redirect_http_code":301,"redirect_url":"http://images.example.com","name":"redirect-images.example.com","action":"REDIRECT_TO_URL","position":1,"tags":["updated_tag"]}}' http://198.51.100.10:9876/v2/lbaas/l7policies/8a1412f0-4c32-4257-8b07-af4770b604fd

View File

@ -2,6 +2,7 @@
"l7policy": {
"description": "Redirect requests to images.example.com",
"admin_state_up": true,
"redirect_http_code": 301,
"redirect_url": "http://images.example.com",
"name": "redirect-images.example.com",
"action": "REDIRECT_TO_URL",

View File

@ -12,6 +12,7 @@
"created_at": "2017-06-24T23:25:14",
"provisioning_status": "PENDING_UPDATE",
"updated_at": "2017-06-24T23:30:05",
"redirect_http_code": 301,
"redirect_pool_id": null,
"redirect_prefix": null,
"redirect_url": "http://www.example.com",

View File

@ -56,6 +56,7 @@ Response Parameters
- position: l7policy-position
- project_id: project_id
- provisioning_status: provisioning_status
- redirect_http_code: l7policy-redirect-http-code
- redirect_pool_id: l7policy-redirect-pool_id
- redirect_prefix: l7policy-redirect-prefix
- redirect_url: l7policy-redirect-url
@ -106,8 +107,10 @@ creating multiple policies with the same action.
If a new policy is created with a position that matches that of an existing
policy, then the new policy is inserted at the given position.
L7 policies with ``action`` of ``REDIRECT_TO_URL`` will return a HTTP
``Found (302)`` response code with the ``redirect_url``.
L7 policies with ``action`` of ``REDIRECT_TO_URL`` will return the default HTTP
``Found (302)`` response code with the ``redirect_url``. Also, specify
``redirect_http_code`` to configure the needed HTTP response code, such as,
301, 302, 303, 307 and 308.
L7 policies with ``action`` of ``REJECT`` will return a ``Forbidden (403)``
response code to the requester.
@ -140,6 +143,7 @@ Request
- name: name-optional
- position: l7policy-position-optional
- project_id: project_id-optional
- redirect_http_code: l7policy-redirect-http-code-optional
- redirect_pool_id: l7policy-redirect-pool_id-optional
- redirect_prefix: l7policy-redirect-prefix-optional
- redirect_url: l7policy-redirect-url-optional
@ -173,6 +177,7 @@ Response Parameters
- position: l7policy-position
- project_id: project_id
- provisioning_status: provisioning_status
- redirect_http_code: l7policy-redirect-http-code
- redirect_pool_id: l7policy-redirect-pool_id
- redirect_prefix: l7policy-redirect-prefix
- redirect_url: l7policy-redirect-url
@ -240,6 +245,7 @@ Response Parameters
- position: l7policy-position
- project_id: project_id
- provisioning_status: provisioning_status
- redirect_http_code: l7policy-redirect-http-code
- redirect_pool_id: l7policy-redirect-pool_id
- redirect_prefix: l7policy-redirect-prefix
- redirect_url: l7policy-redirect-url
@ -297,6 +303,7 @@ Request
- l7policy_id: path-l7policy-id
- name: name-optional
- position: l7policy-position-optional
- redirect_http_code: l7policy-redirect-http-code-optional
- redirect_pool_id: l7policy-redirect-pool_id-optional
- redirect_prefix: l7policy-redirect-prefix-optional
- redirect_url: l7policy-redirect-url-optional
@ -330,6 +337,7 @@ Response Parameters
- position: l7policy-position
- project_id: project_id
- provisioning_status: provisioning_status
- redirect_http_code: l7policy-redirect-http-code
- redirect_pool_id: l7policy-redirect-pool_id
- redirect_prefix: l7policy-redirect-prefix
- redirect_url: l7policy-redirect-url

View File

@ -238,7 +238,7 @@ class L7Policy(BaseDataModel):
def __init__(self, action=Unset, admin_state_up=Unset, description=Unset,
l7policy_id=Unset, listener_id=Unset, name=Unset,
position=Unset, redirect_pool_id=Unset, redirect_url=Unset,
rules=Unset, redirect_prefix=Unset):
rules=Unset, redirect_prefix=Unset, redirect_http_code=Unset):
self.action = action
self.admin_state_up = admin_state_up
@ -251,6 +251,7 @@ class L7Policy(BaseDataModel):
self.redirect_url = redirect_url
self.rules = rules
self.redirect_prefix = redirect_prefix
self.redirect_http_code = redirect_http_code
class L7Rule(BaseDataModel):

View File

@ -92,6 +92,9 @@ class RootController(rest.RestController):
self._add_a_version(versions, 'v2.7', 'v2', 'SUPPORTED',
'2018-01-25T12:00:00Z', host_url)
# TLS client authentication
self._add_a_version(versions, 'v2.8', 'v2', 'CURRENT',
self._add_a_version(versions, 'v2.8', 'v2', 'SUPPORTED',
'2019-02-12T00:00:00Z', host_url)
# HTTP Redirect code
self._add_a_version(versions, 'v2.9', 'v2', 'CURRENT',
'2019-03-04T00:00:00Z', host_url)
return {'versions': versions}

View File

@ -95,6 +95,12 @@ class L7PolicyController(base.BaseController):
def _validate_create_l7policy(self, lock_session, l7policy_dict):
try:
# Set the default HTTP redirect code here so it's explicit
if ((l7policy_dict.get('redirect_url') or
l7policy_dict.get('redirect_prefix')) and
not l7policy_dict.get('redirect_http_code')):
l7policy_dict['redirect_http_code'] = 302
return self.repositories.l7policy.create(lock_session,
**l7policy_dict)
except odb_exceptions.DBDuplicateEntry:

View File

@ -44,6 +44,7 @@ class L7PolicyResponse(BaseL7PolicyType):
created_at = wtypes.wsattr(wtypes.datetime.datetime)
updated_at = wtypes.wsattr(wtypes.datetime.datetime)
tags = wtypes.wsattr(wtypes.ArrayType(wtypes.StringType()))
redirect_http_code = wtypes.wsattr(wtypes.IntegerType())
@classmethod
def from_data_model(cls, data_model, children=False):
@ -96,6 +97,8 @@ class L7PolicyPOST(BaseL7PolicyType):
listener_id = wtypes.wsattr(wtypes.UuidType(), mandatory=True)
rules = wtypes.wsattr([l7rule.L7RuleSingleCreate])
tags = wtypes.wsattr(wtypes.ArrayType(wtypes.StringType(max_length=255)))
redirect_http_code = wtypes.wsattr(
wtypes.Enum(int, *constants.SUPPORTED_L7POLICY_REDIRECT_HTTP_CODES))
class L7PolicyRootPOST(types.BaseType):
@ -116,6 +119,8 @@ class L7PolicyPUT(BaseL7PolicyType):
minimum=constants.MIN_POLICY_POSITION,
maximum=constants.MAX_POLICY_POSITION))
tags = wtypes.wsattr(wtypes.ArrayType(wtypes.StringType(max_length=255)))
redirect_http_code = wtypes.wsattr(
wtypes.Enum(int, *constants.SUPPORTED_L7POLICY_REDIRECT_HTTP_CODES))
class L7PolicyRootPUT(types.BaseType):
@ -139,3 +144,5 @@ class L7PolicySingleCreate(BaseL7PolicyType):
default=constants.MAX_POLICY_POSITION)
rules = wtypes.wsattr([l7rule.L7RuleSingleCreate])
tags = wtypes.wsattr(wtypes.ArrayType(wtypes.StringType(max_length=255)))
redirect_http_code = wtypes.wsattr(
wtypes.Enum(int, *constants.SUPPORTED_L7POLICY_REDIRECT_HTTP_CODES))

View File

@ -173,6 +173,9 @@ SUPPORTED_L7POLICY_ACTIONS = (L7POLICY_ACTION_REJECT,
L7POLICY_ACTION_REDIRECT_TO_POOL,
L7POLICY_ACTION_REDIRECT_PREFIX)
# For redirect, only codes 301, 302, 303, 307 and 308 are # supported.
SUPPORTED_L7POLICY_REDIRECT_HTTP_CODES = [301, 302, 303, 307, 308]
MIN_POLICY_POSITION = 1
# Largest a 32-bit integer can be, which is a limitation
# here if you're using MySQL, as most probably are. This just needs

View File

@ -620,7 +620,8 @@ class L7Policy(BaseDataModel):
position=None, listener=None, redirect_pool=None,
enabled=None, l7rules=None, provisioning_status=None,
operating_status=None, project_id=None, created_at=None,
updated_at=None, redirect_prefix=None, tags=None):
updated_at=None, redirect_prefix=None, tags=None,
redirect_http_code=None):
self.id = id
self.name = name
self.description = description
@ -640,6 +641,7 @@ class L7Policy(BaseDataModel):
self.updated_at = updated_at
self.redirect_prefix = redirect_prefix
self.tags = tags
self.redirect_http_code = redirect_http_code
def _conditionally_remove_pool_links(self, pool):
"""Removes links to the given pool from parent objects.
@ -666,6 +668,7 @@ class L7Policy(BaseDataModel):
self._conditionally_remove_pool_links(self.redirect_pool)
self.action = constants.L7POLICY_ACTION_REDIRECT_TO_POOL
self.redirect_url = None
self.redirect_http_code = None
pool = self._find_in_graph('Pool' + value)
self.redirect_pool = pool
if self.l7rules and (self.enabled is True or (
@ -685,6 +688,7 @@ class L7Policy(BaseDataModel):
self._conditionally_remove_pool_links(self.redirect_pool)
self.redirect_pool = None
self.redirect_pool_id = None
self.redirect_http_code = None
elif key == 'position':
self.listener.l7policies.remove(self)
self.listener.l7policies.insert(value - 1, self)

View File

@ -397,6 +397,12 @@ class JinjaTemplater(object):
l7policy.redirect_pool, feature_compatibility, **kwargs)
else:
ret_value['redirect_pool'] = None
if (l7policy.action in [constants.L7POLICY_ACTION_REDIRECT_TO_URL,
constants.L7POLICY_ACTION_REDIRECT_PREFIX] and
l7policy.redirect_http_code):
ret_value['redirect_http_code'] = l7policy.redirect_http_code
else:
ret_value['redirect_http_code'] = None
l7rules = [self._transform_l7rule(x, feature_compatibility)
for x in l7policy.l7rules if x.enabled]
ret_value['l7rules'] = l7rules

View File

@ -116,16 +116,22 @@ bind {{ lb_vip_address }}:{{ listener.protocol_port }} {{
{% for l7rule in l7policy.l7rules %}
{{- l7rule_macro(constants, l7rule) -}}
{% endfor %}
{% if l7policy.redirect_http_code %}
{% set redirect_http_code_opt = " code %s"|format(
l7policy.redirect_http_code) %}
{% else %}
{% set redirect_http_code_opt = "" %}
{% endif %}
{% if l7policy.action == constants.L7POLICY_ACTION_REJECT %}
http-request deny if{{ l7rule_list_macro(l7policy) }}
{% elif l7policy.action == constants.L7POLICY_ACTION_REDIRECT_TO_URL %}
redirect location {{ l7policy.redirect_url }} if{{ l7rule_list_macro(
redirect {{- redirect_http_code_opt }} location {{ l7policy.redirect_url }} if{{ l7rule_list_macro(
l7policy) }}
{% elif l7policy.action == constants.L7POLICY_ACTION_REDIRECT_TO_POOL and l7policy.redirect_pool.enabled %}
use_backend {{ l7policy.redirect_pool.id }} if{{ l7rule_list_macro(
l7policy) }}
{% elif l7policy.action == constants.L7POLICY_ACTION_REDIRECT_PREFIX %}
redirect prefix {{ l7policy.redirect_prefix }} if{{ l7rule_list_macro(
redirect {{- redirect_http_code_opt }} prefix {{ l7policy.redirect_prefix }} if{{ l7rule_list_macro(
l7policy) }}
{% endif %}
{% endmacro %}

View File

@ -274,12 +274,14 @@ def sanitize_l7policy_api_args(l7policy, create=False):
l7policy.update({'redirect_url': None})
l7policy.pop('redirect_pool', None)
l7policy.update({'redirect_prefix': None})
l7policy.update({'redirect_http_code': None})
if l7policy.get('redirect_pool'):
l7policy.update({
'action': constants.L7POLICY_ACTION_REDIRECT_TO_POOL})
l7policy.update({'redirect_url': None})
l7policy.pop('redirect_pool_id', None)
l7policy.update({'redirect_prefix': None})
l7policy.update({'redirect_http_code': None})
if l7policy.get('redirect_url'):
url(l7policy['redirect_url'])
l7policy.update({
@ -287,6 +289,8 @@ def sanitize_l7policy_api_args(l7policy, create=False):
l7policy.update({'redirect_pool_id': None})
l7policy.update({'redirect_prefix': None})
l7policy.pop('redirect_pool', None)
if not l7policy.get('redirect_http_code'):
l7policy.update({'redirect_http_code': 302})
if l7policy.get('redirect_prefix'):
url(l7policy['redirect_prefix'])
l7policy.update({
@ -294,6 +298,8 @@ def sanitize_l7policy_api_args(l7policy, create=False):
l7policy.update({'redirect_pool_id': None})
l7policy.update({'redirect_url': None})
l7policy.pop('redirect_pool', None)
if not l7policy.get('redirect_http_code'):
l7policy.update({'redirect_http_code': 302})
# If we are creating, we need an action at this point
if create and 'action' not in l7policy.keys():

View File

@ -0,0 +1,36 @@
#
# 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 L7policy Redirect http code
Revision ID: 6742ca1b27c2
Revises: a7f187cd221f
Create Date: 2018-12-13 09:35:38.780054
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '6742ca1b27c2'
down_revision = 'a7f187cd221f'
def upgrade():
# Add collumn redirect_prefix
op.add_column(
u'l7policy',
sa.Column(u'redirect_http_code', sa.Integer(), nullable=True)
)

View File

@ -689,6 +689,7 @@ class L7Policy(base_models.BASE, base_models.IdMixin, base_models.ProjectMixin,
redirect_prefix = sa.Column(
sa.String(255),
nullable=True)
redirect_http_code = sa.Column(sa.Integer, nullable=True)
position = sa.Column(sa.Integer, nullable=False)
enabled = sa.Column(sa.Boolean(), nullable=False)
listener = orm.relationship("Listener", uselist=False,

View File

@ -1654,6 +1654,7 @@ class L7PolicyRepository(BaseRepository):
model_kwargs.update(redirect_url=None)
model_kwargs.update(redirect_pool_id=None)
model_kwargs.update(redirect_prefix=None)
model_kwargs.update(redirect_http_code=None)
elif (l7policy.action ==
consts.L7POLICY_ACTION_REDIRECT_TO_URL):
model_kwargs.update(redirect_pool_id=None)
@ -1662,6 +1663,7 @@ class L7PolicyRepository(BaseRepository):
consts.L7POLICY_ACTION_REDIRECT_TO_POOL):
model_kwargs.update(redirect_url=None)
model_kwargs.update(redirect_prefix=None)
model_kwargs.update(redirect_http_code=None)
elif (l7policy.action ==
consts.L7POLICY_ACTION_REDIRECT_PREFIX):
model_kwargs.update(redirect_url=None)

View File

@ -46,7 +46,7 @@ class TestRootController(base_db_test.OctaviaDBTestBase):
versions = self._get_versions_with_config(
api_v1_enabled=True, api_v2_enabled=True)
version_ids = tuple(v.get('id') for v in versions)
self.assertEqual(10, len(version_ids))
self.assertEqual(11, len(version_ids))
self.assertIn('v1', version_ids)
self.assertIn('v2.0', version_ids)
self.assertIn('v2.1', version_ids)
@ -57,6 +57,7 @@ class TestRootController(base_db_test.OctaviaDBTestBase):
self.assertIn('v2.6', version_ids)
self.assertIn('v2.7', version_ids)
self.assertIn('v2.8', version_ids)
self.assertIn('v2.9', version_ids)
# Each version should have a 'self' 'href' to the API version URL
# [{u'rel': u'self', u'href': u'http://localhost/v2'}]
@ -76,7 +77,7 @@ class TestRootController(base_db_test.OctaviaDBTestBase):
def test_api_v1_disabled(self):
versions = self._get_versions_with_config(
api_v1_enabled=False, api_v2_enabled=True)
self.assertEqual(9, len(versions))
self.assertEqual(10, len(versions))
self.assertEqual('v2.0', versions[0].get('id'))
self.assertEqual('v2.1', versions[1].get('id'))
self.assertEqual('v2.2', versions[2].get('id'))
@ -86,6 +87,7 @@ class TestRootController(base_db_test.OctaviaDBTestBase):
self.assertEqual('v2.6', versions[6].get('id'))
self.assertEqual('v2.7', versions[7].get('id'))
self.assertEqual('v2.8', versions[8].get('id'))
self.assertEqual('v2.9', versions[9].get('id'))
def test_api_v2_disabled(self):
versions = self._get_versions_with_config(

View File

@ -703,6 +703,61 @@ class TestL7Policy(base.BaseAPITest):
l7policy_prov_status=constants.PENDING_CREATE,
l7policy_op_status=constants.OFFLINE)
def test_create_with_redirect_http_code(self):
action_key_values = {
constants.L7POLICY_ACTION_REDIRECT_PREFIX: {
'redirect_prefix': 'https://example.com',
'redirect_http_code': 302},
constants.L7POLICY_ACTION_REDIRECT_TO_URL: {
'redirect_url': 'http://www.example.com',
'redirect_http_code': 301}}
count = 1
# First, test with redirect actions
for action in [constants.L7POLICY_ACTION_REDIRECT_TO_URL,
constants.L7POLICY_ACTION_REDIRECT_PREFIX]:
api_l7policy = self.create_l7policy(
self.listener_id, action,
**action_key_values[action]).get(self.root_tag)
self.assertEqual(action, api_l7policy['action'])
self.assertEqual(count, api_l7policy['position'])
self.assertIsNone(api_l7policy.get('redirect_pool_id'))
if api_l7policy.get('redirect_url'):
self.assertEqual(action_key_values[action]['redirect_url'],
api_l7policy['redirect_url'])
elif api_l7policy.get('redirect_prefix'):
self.assertEqual(action_key_values[action]['redirect_prefix'],
api_l7policy['redirect_prefix'])
self.assertEqual(action_key_values[action]['redirect_http_code'],
api_l7policy['redirect_http_code'])
self.assert_correct_status(
lb_id=self.lb_id, listener_id=self.listener_id,
l7policy_id=api_l7policy.get('id'),
lb_prov_status=constants.PENDING_UPDATE,
listener_prov_status=constants.PENDING_UPDATE,
l7policy_prov_status=constants.PENDING_CREATE,
l7policy_op_status=constants.OFFLINE)
self.set_lb_status(self.lb_id)
count += 1
# test with redirect_pool action
api_l7policy = self.create_l7policy(
self.listener_id, constants.L7POLICY_ACTION_REDIRECT_TO_POOL,
redirect_pool_id=self.pool_id,
redirect_http_code=308).get(self.root_tag)
self.assertEqual(constants.L7POLICY_ACTION_REDIRECT_TO_POOL,
api_l7policy['action'])
self.assertEqual(self.pool_id, api_l7policy.get('redirect_pool_id'))
self.assertIsNone(api_l7policy.get('redirect_url'))
self.assertIsNone(api_l7policy.get('redirect_prefix'))
self.assertIsNone(api_l7policy.get('redirect_http_code'))
self.assert_correct_status(
lb_id=self.lb_id, listener_id=self.listener_id,
l7policy_id=api_l7policy.get('id'),
lb_prov_status=constants.PENDING_UPDATE,
listener_prov_status=constants.PENDING_UPDATE,
l7policy_prov_status=constants.PENDING_CREATE,
l7policy_op_status=constants.OFFLINE)
def test_bad_create(self):
l7policy = {'listener_id': self.listener_id,
'name': 'test1'}
@ -736,6 +791,15 @@ class TestL7Policy(base.BaseAPITest):
'redirect_url': 'bad url'}
self.post(self.L7POLICIES_PATH, self._build_body(l7policy), status=400)
def test_bad_create_with_redirect_http_code(self):
for test_code in [1, '', 'HTTPCODE']:
l7policy = {'listener_id': self.listener_id,
'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
'redirect_url': 'http://www.example.com',
'redirect_http_code': test_code}
self.post(self.L7POLICIES_PATH, self._build_body(l7policy),
status=400)
@mock.patch('octavia.api.drivers.utils.call_provider')
def test_create_with_bad_provider(self, mock_provider):
mock_provider.side_effect = exceptions.ProviderDriverError(
@ -958,6 +1022,61 @@ class TestL7Policy(base.BaseAPITest):
self.put(self.L7POLICY_PATH.format(l7policy_id=api_l7policy.get('id')),
self._build_body(new_l7policy))
def test_update_with_redirect_http_code(self):
# test from non exist
api_l7policy = self.create_l7policy(self.listener_id,
constants.L7POLICY_ACTION_REJECT,
).get(self.root_tag)
self.set_lb_status(self.lb_id)
new_l7policy = {
'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
'redirect_url': 'http://www.example.com',
'redirect_http_code': 308}
response = self.put(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id')),
self._build_body(new_l7policy)).json.get(self.root_tag)
self.assertEqual(constants.L7POLICY_ACTION_REDIRECT_TO_URL,
response.get('action'))
self.assertEqual(308, response.get('redirect_http_code'))
self.set_lb_status(self.lb_id)
# test from exist to new
api_l7policy = self.create_l7policy(
self.listener_id, constants.L7POLICY_ACTION_REDIRECT_TO_URL,
redirect_url='http://www.example.com',
redirect_http_code=302).get(self.root_tag)
self.set_lb_status(self.lb_id)
new_l7policy = {
'redirect_http_code': 308}
response = self.put(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id')),
self._build_body(new_l7policy)).json.get(self.root_tag)
self.assertEqual(constants.L7POLICY_ACTION_REDIRECT_TO_URL,
response.get('action'))
self.assertEqual(308, response.get('redirect_http_code'))
self.set_lb_status(self.lb_id)
# test from exist to null
new_l7policy = {
'redirect_http_code': None}
response = self.put(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id')),
self._build_body(new_l7policy)).json.get(self.root_tag)
self.assertIsNone(response.get('redirect_http_code'))
def test_bad_update_with_redirect_http_code(self):
api_l7policy = self.create_l7policy(self.listener_id,
constants.L7POLICY_ACTION_REJECT,
).get(self.root_tag)
self.set_lb_status(self.lb_id)
new_l7policy = {
'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
'redirect_url': 'http://www.example.com',
'redirect_http_code': ''}
self.put(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id')),
self._build_body(new_l7policy), status=400).json.get(self.root_tag)
def test_delete(self):
api_l7policy = self.create_l7policy(
self.listener_id,

View File

@ -2523,12 +2523,14 @@ class TestLoadBalancerGraph(base.BaseAPITest):
'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
'redirect_url': 'http://127.0.0.1/',
'position': 1,
'redirect_http_code': 302,
'admin_state_up': False
}
create_l7policies.append(create_l7policy)
expected_l7policy = {
'name': '',
'description': '',
'redirect_http_code': None,
'redirect_url': None,
'redirect_prefix': None,
'rules': [],

View File

@ -337,7 +337,8 @@ class SampleDriverDataModels(object):
'position': 1,
'listener': None,
'redirect_pool': None,
'l7rules': self.test_l7rules}
'l7rules': self.test_l7rules,
'redirect_http_code': 302}
self.test_l7policy1_dict.update(self._common_test_dict)
@ -367,7 +368,8 @@ class SampleDriverDataModels(object):
'redirect_pool_id': self.pool1_id,
'redirect_url': '/index.html',
'redirect_prefix': 'https://example.com/',
'rules': self.provider_l7rules_dicts
'rules': self.provider_l7rules_dicts,
'redirect_http_code': 302
}
self.provider_l7policy2_dict = copy.deepcopy(

View File

@ -612,7 +612,7 @@ class TestHaproxyCfg(base.TestCase):
"This\\ string\\\\\\ with\\ stuff\n"
" acl sample_l7rule_id_3 req.cook(some-cookie) -m reg "
"this.*|that\n"
" redirect location http://www.example.com if "
" redirect code 302 location http://www.example.com if "
"!sample_l7rule_id_2 sample_l7rule_id_3\n"
" acl sample_l7rule_id_4 path_end -m str jpg\n"
" acl sample_l7rule_id_5 req.hdr(host) -i -m end "
@ -623,7 +623,7 @@ class TestHaproxyCfg(base.TestCase):
"This\\ string\\\\\\ with\\ stuff\n"
" acl sample_l7rule_id_3 req.cook(some-cookie) -m reg "
"this.*|that\n"
" redirect prefix https://example.com if "
" redirect code 302 prefix https://example.com if "
"!sample_l7rule_id_2 sample_l7rule_id_3\n"
" default_backend sample_pool_id_1\n"
" timeout client 50000\n\n").format(
@ -901,12 +901,18 @@ class TestHaproxyCfg(base.TestCase):
ret = self.jinja_cfg._transform_l7policy(in_l7policy, {})
self.assertEqual(sample_configs.RET_L7POLICY_1, ret)
def test_transform_l7policy_2(self):
def test_transform_l7policy_2_8(self):
in_l7policy = sample_configs.sample_l7policy_tuple(
'sample_l7policy_id_2', sample_policy=2)
ret = self.jinja_cfg._transform_l7policy(in_l7policy, {})
self.assertEqual(sample_configs.RET_L7POLICY_2, ret)
# test invalid action without redirect_http_code
in_l7policy = sample_configs.sample_l7policy_tuple(
'sample_l7policy_id_8', sample_policy=2, redirect_http_code=None)
ret = self.jinja_cfg._transform_l7policy(in_l7policy, {})
self.assertEqual(sample_configs.RET_L7POLICY_8, ret)
def test_transform_l7policy_disabled_rule(self):
in_l7policy = sample_configs.sample_l7policy_tuple(
'sample_l7policy_id_6', sample_policy=6)
@ -1046,7 +1052,7 @@ class TestHaproxyCfg(base.TestCase):
"This\\ string\\\\\\ with\\ stuff\n"
" acl sample_l7rule_id_3 req.cook(some-cookie) -m reg "
"this.*|that\n"
" redirect location http://www.example.com "
" redirect code 302 location http://www.example.com "
"if !sample_l7rule_id_2 sample_l7rule_id_3\n"
" acl sample_l7rule_id_4 path_end -m str jpg\n"
" acl sample_l7rule_id_5 req.hdr(host) -i -m end "
@ -1057,7 +1063,7 @@ class TestHaproxyCfg(base.TestCase):
"This\\ string\\\\\\ with\\ stuff\n"
" acl sample_l7rule_id_3 req.cook(some-cookie) -m reg "
"this.*|that\n"
" redirect prefix https://example.com "
" redirect code 302 prefix https://example.com "
"if !sample_l7rule_id_2 sample_l7rule_id_3\n"
" acl sample_l7rule_id_7 ssl_c_used\n"
" acl sample_l7rule_id_8 ssl_c_verify eq 1\n"
@ -1066,7 +1072,8 @@ class TestHaproxyCfg(base.TestCase):
" acl sample_l7rule_id_10 ssl_c_s_dn(OU-3) -m beg "
"Orgnization\\ Bala\n"
" acl sample_l7rule_id_11 path -m beg /api\n"
" redirect location http://www.ssl-type-l7rule-test.com "
" redirect code 302 location "
"http://www.ssl-type-l7rule-test.com "
"if sample_l7rule_id_7 !sample_l7rule_id_8 !sample_l7rule_id_9 "
"!sample_l7rule_id_10 sample_l7rule_id_11\n"
" default_backend sample_pool_id_1\n"

View File

@ -208,7 +208,8 @@ RET_L7POLICY_1 = {
'redirect_url': None,
'redirect_prefix': None,
'enabled': True,
'l7rules': [RET_L7RULE_1]}
'l7rules': [RET_L7RULE_1],
'redirect_http_code': None}
RET_L7POLICY_2 = {
'id': 'sample_l7policy_id_2',
@ -217,7 +218,8 @@ RET_L7POLICY_2 = {
'redirect_url': 'http://www.example.com',
'redirect_prefix': None,
'enabled': True,
'l7rules': [RET_L7RULE_2, RET_L7RULE_3]}
'l7rules': [RET_L7RULE_2, RET_L7RULE_3],
'redirect_http_code': 302}
RET_L7POLICY_3 = {
'id': 'sample_l7policy_id_3',
@ -226,7 +228,8 @@ RET_L7POLICY_3 = {
'redirect_url': None,
'redirect_prefix': None,
'enabled': True,
'l7rules': [RET_L7RULE_4, RET_L7RULE_5]}
'l7rules': [RET_L7RULE_4, RET_L7RULE_5],
'redirect_http_code': None}
RET_L7POLICY_4 = {
'id': 'sample_l7policy_id_4',
@ -235,7 +238,8 @@ RET_L7POLICY_4 = {
'redirect_url': None,
'redirect_prefix': None,
'enabled': True,
'l7rules': []}
'l7rules': [],
'redirect_http_code': None}
RET_L7POLICY_5 = {
'id': 'sample_l7policy_id_5',
@ -244,7 +248,8 @@ RET_L7POLICY_5 = {
'redirect_url': None,
'redirect_prefix': None,
'enabled': False,
'l7rules': [RET_L7RULE_5]}
'l7rules': [RET_L7RULE_5],
'redirect_http_code': None}
RET_L7POLICY_6 = {
'id': 'sample_l7policy_id_6',
@ -253,7 +258,8 @@ RET_L7POLICY_6 = {
'redirect_url': None,
'redirect_prefix': None,
'enabled': True,
'l7rules': []}
'l7rules': [],
'redirect_http_code': None}
RET_L7POLICY_7 = {
'id': 'sample_l7policy_id_7',
@ -262,7 +268,18 @@ RET_L7POLICY_7 = {
'redirect_url': None,
'redirect_prefix': 'https://example.com',
'enabled': True,
'l7rules': [RET_L7RULE_2, RET_L7RULE_3]}
'l7rules': [RET_L7RULE_2, RET_L7RULE_3],
'redirect_http_code': 302}
RET_L7POLICY_8 = {
'id': 'sample_l7policy_id_8',
'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
'redirect_pool': None,
'redirect_url': 'http://www.example.com',
'redirect_prefix': None,
'enabled': True,
'l7rules': [RET_L7RULE_2, RET_L7RULE_3],
'redirect_http_code': None}
RET_LISTENER = {
'id': 'sample_listener_id_1',
@ -813,11 +830,13 @@ def sample_l7policy_tuple(id,
action=constants.L7POLICY_ACTION_REJECT,
redirect_pool=None, redirect_url=None,
redirect_prefix=None,
enabled=True, sample_policy=1):
enabled=True, redirect_http_code=302,
sample_policy=1):
in_l7policy = collections.namedtuple('l7policy',
'id, action, redirect_pool, '
'redirect_url, redirect_prefix, '
'l7rules, enabled')
'l7rules, enabled,'
'redirect_http_code')
l7rules = []
if sample_policy == 1:
action = constants.L7POLICY_ACTION_REDIRECT_TO_POOL
@ -861,7 +880,11 @@ def sample_l7policy_tuple(id,
redirect_url=redirect_url,
redirect_prefix=redirect_prefix,
l7rules=l7rules,
enabled=enabled)
enabled=enabled,
redirect_http_code=redirect_http_code
if (action in [constants.L7POLICY_ACTION_REDIRECT_TO_URL,
constants.L7POLICY_ACTION_REDIRECT_PREFIX] and
redirect_http_code) else None)
def sample_l7rule_tuple(id,

View File

@ -0,0 +1,6 @@
---
features:
- Now Octavia L7Policy API can accept an new option `redirect_http_code`
for L7Policy actions `REDIRECT_URL` or `REDIRECT_PREFIX`, then each HTTP
requests to the associated Listener will return the configured HTTP
response code.