Support REDIRECT_PREFIX action for L7Policy

Currently, Octavia only support three actions for L7Policy,
in this patch we will implement new action for L7Policy.

Story: 2003700

Change-Id: Ie99591ede097b566294ebdb673c460442dd6d942
This commit is contained in:
sapd 2018-09-09 22:30:58 +07:00
parent 7fa83ef8e6
commit 62192dba3a
24 changed files with 173 additions and 21 deletions

View File

@ -523,6 +523,20 @@ l7policy-redirect-pool_id-optional:
in: body
required: false
type: uuid
l7policy-redirect-prefix:
description: |
Requests matching this policy will be redirected to this Prefix URL.
Only valid if ``action`` is ``REDIRECT_PREFIX``.
in: body
required: true
type: string
l7policy-redirect-prefix-optional:
description: |
Requests matching this policy will be redirected to this Prefix URL.
Only valid if ``action`` is ``REDIRECT_PREFIX``.
in: body
required: false
type: string
l7policy-redirect-url:
description: |
Requests matching this policy will be redirected to this URL.

View File

@ -13,6 +13,7 @@
"provisioning_status": "ACTIVE",
"updated_at": "2017-06-24T23:30:05",
"redirect_pool_id": null,
"redirect_prefix": null,
"redirect_url": "http://www.example.com",
"action": "REDIRECT_TO_URL",
"position": 1,

View File

@ -13,6 +13,7 @@
"provisioning_status": "PENDING_CREATE",
"updated_at": "2017-06-24T23:30:05",
"redirect_pool_id": null,
"redirect_prefix": null,
"redirect_url": "http://www.example.com",
"action": "REDIRECT_TO_URL",
"position": 1,

View File

@ -13,6 +13,7 @@
"provisioning_status": "ACTIVE",
"updated_at": "2017-06-24T23:30:05",
"redirect_pool_id": null,
"redirect_prefix": null,
"redirect_url": "http://www.example.com",
"action": "REDIRECT_TO_URL",
"position": 1,

View File

@ -13,6 +13,7 @@
"provisioning_status": "PENDING_UPDATE",
"updated_at": "2017-06-24T23:30:05",
"redirect_pool_id": null,
"redirect_prefix": null,
"redirect_url": "http://www.example.com",
"action": "REDIRECT_TO_URL",
"position": 1,

View File

@ -57,6 +57,7 @@ Response Parameters
- project_id: project_id
- provisioning_status: provisioning_status
- redirect_pool_id: l7policy-redirect-pool_id
- redirect_prefix: l7policy-redirect-prefix
- redirect_url: l7policy-redirect-url
- rules: l7policy-rule-ids
- updated_at: updated_at
@ -139,6 +140,7 @@ Request
- position: l7policy-position-optional
- project_id: project_id-optional
- redirect_pool_id: l7policy-redirect-pool_id-optional
- redirect_prefix: l7policy-redirect-prefix-optional
- redirect_url: l7policy-redirect-url-optional
Request Example
@ -170,6 +172,7 @@ Response Parameters
- project_id: project_id
- provisioning_status: provisioning_status
- redirect_pool_id: l7policy-redirect-pool_id
- redirect_prefix: l7policy-redirect-prefix
- redirect_url: l7policy-redirect-url
- rules: l7policy-rule-ids
- updated_at: updated_at
@ -235,6 +238,7 @@ Response Parameters
- project_id: project_id
- provisioning_status: provisioning_status
- redirect_pool_id: l7policy-redirect-pool_id
- redirect_prefix: l7policy-redirect-prefix
- redirect_url: l7policy-redirect-url
- rules: l7policy-rule-ids
- updated_at: updated_at
@ -290,6 +294,7 @@ Request
- name: name-optional
- position: l7policy-position-optional
- redirect_pool_id: l7policy-redirect-pool_id-optional
- redirect_prefix: l7policy-redirect-prefix-optional
- redirect_url: l7policy-redirect-url-optional
Request Example
@ -321,6 +326,7 @@ Response Parameters
- project_id: project_id
- provisioning_status: provisioning_status
- redirect_pool_id: l7policy-redirect-pool_id
- redirect_prefix: l7policy-redirect-prefix
- redirect_url: l7policy-redirect-url
- rules: l7policy-rule-ids
- updated_at: updated_at

View File

@ -60,7 +60,7 @@ Redirect *http://www.example.com/* to *https://www.example.com/*
.. code-block:: bash
openstack loadbalancer listener create --name http_listener --protocol HTTP --protocol-port 80 lb1
openstack loadbalancer l7policy create --action REDIRECT_TO_URL --redirect-url https://www.example.com/ --name policy1 http_listener
openstack loadbalancer l7policy create --action REDIRECT_PREFIX --redirect-prefix https://www.example.com/ --name policy1 http_listener
openstack loadbalancer l7rule create --compare-type STARTS_WITH --type PATH --value / policy1

View File

@ -220,7 +220,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):
rules=Unset, redirect_prefix=Unset):
self.action = action
self.admin_state_up = admin_state_up
@ -232,6 +232,7 @@ class L7Policy(BaseDataModel):
self.redirect_pool_id = redirect_pool_id
self.redirect_url = redirect_url
self.rules = rules
self.redirect_prefix = redirect_prefix
class L7Rule(BaseDataModel):

View File

@ -29,6 +29,7 @@ class L7PolicyResponse(base.BaseType):
action = wtypes.wsattr(wtypes.StringType())
redirect_pool_id = wtypes.wsattr(wtypes.UuidType())
redirect_url = wtypes.wsattr(wtypes.StringType())
redirect_prefix = wtypes.wsattr(wtypes.StringType())
position = wtypes.wsattr(wtypes.IntegerType())
l7rules = wtypes.wsattr([l7rule.L7RuleResponse])
redirect_pool = wtypes.wsattr(pool.PoolResponse)
@ -66,6 +67,7 @@ class L7PolicyPOST(base.BaseType):
mandatory=True)
redirect_pool_id = wtypes.wsattr(wtypes.UuidType())
redirect_url = wtypes.wsattr(base.URLType())
redirect_prefix = wtypes.wsattr(base.URLType())
position = wtypes.wsattr(wtypes.IntegerType(),
default=constants.MAX_POLICY_POSITION)
redirect_pool = wtypes.wsattr(pool.PoolPOST)
@ -81,4 +83,5 @@ class L7PolicyPUT(base.BaseType):
wtypes.Enum(str, *constants.SUPPORTED_L7POLICY_ACTIONS))
redirect_pool_id = wtypes.wsattr(wtypes.UuidType())
redirect_url = wtypes.wsattr(base.URLType())
redirect_prefix = wtypes.wsattr(base.URLType())
position = wtypes.wsattr(wtypes.IntegerType())

View File

@ -38,6 +38,7 @@ class L7PolicyResponse(BaseL7PolicyType):
listener_id = wtypes.wsattr(wtypes.UuidType())
redirect_pool_id = wtypes.wsattr(wtypes.UuidType())
redirect_url = wtypes.wsattr(wtypes.StringType())
redirect_prefix = wtypes.wsattr(wtypes.StringType())
position = wtypes.wsattr(wtypes.IntegerType())
rules = wtypes.wsattr([types.IdOnlyType])
created_at = wtypes.wsattr(wtypes.datetime.datetime)
@ -86,6 +87,7 @@ class L7PolicyPOST(BaseL7PolicyType):
mandatory=True)
redirect_pool_id = wtypes.wsattr(wtypes.UuidType())
redirect_url = wtypes.wsattr(types.URLType())
redirect_prefix = wtypes.wsattr(types.URLType())
position = wtypes.wsattr(wtypes.IntegerType(
minimum=constants.MIN_POLICY_POSITION,
maximum=constants.MAX_POLICY_POSITION),
@ -107,6 +109,7 @@ class L7PolicyPUT(BaseL7PolicyType):
wtypes.Enum(str, *constants.SUPPORTED_L7POLICY_ACTIONS))
redirect_pool_id = wtypes.wsattr(wtypes.UuidType())
redirect_url = wtypes.wsattr(types.URLType())
redirect_prefix = wtypes.wsattr(types.URLType())
position = wtypes.wsattr(wtypes.IntegerType(
minimum=constants.MIN_POLICY_POSITION,
maximum=constants.MAX_POLICY_POSITION))
@ -126,6 +129,7 @@ class L7PolicySingleCreate(BaseL7PolicyType):
mandatory=True)
redirect_pool = wtypes.wsattr(pool.PoolSingleCreate)
redirect_url = wtypes.wsattr(types.URLType())
redirect_prefix = wtypes.wsattr(types.URLType())
position = wtypes.wsattr(wtypes.IntegerType(
minimum=constants.MIN_POLICY_POSITION,
maximum=constants.MAX_POLICY_POSITION),

View File

@ -161,9 +161,11 @@ SUPPORTED_L7RULE_COMPARE_TYPES = (L7RULE_COMPARE_TYPE_REGEX,
L7POLICY_ACTION_REJECT = 'REJECT'
L7POLICY_ACTION_REDIRECT_TO_URL = 'REDIRECT_TO_URL'
L7POLICY_ACTION_REDIRECT_TO_POOL = 'REDIRECT_TO_POOL'
L7POLICY_ACTION_REDIRECT_PREFIX = 'REDIRECT_PREFIX'
SUPPORTED_L7POLICY_ACTIONS = (L7POLICY_ACTION_REJECT,
L7POLICY_ACTION_REDIRECT_TO_URL,
L7POLICY_ACTION_REDIRECT_TO_POOL)
L7POLICY_ACTION_REDIRECT_TO_POOL,
L7POLICY_ACTION_REDIRECT_PREFIX)
MIN_POLICY_POSITION = 1
# Largest a 32-bit integer can be, which is a limitation

View File

@ -592,7 +592,7 @@ 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):
updated_at=None, redirect_prefix=None):
self.id = id
self.name = name
self.description = description
@ -610,6 +610,7 @@ class L7Policy(BaseDataModel):
self.project_id = project_id
self.created_at = created_at
self.updated_at = updated_at
self.redirect_prefix = redirect_prefix
def _conditionally_remove_pool_links(self, pool):
"""Removes links to the given pool from parent objects.

View File

@ -308,6 +308,7 @@ class JinjaTemplater(object):
'id': l7policy.id,
'action': l7policy.action,
'redirect_url': l7policy.redirect_url,
'redirect_prefix': l7policy.redirect_prefix,
'enabled': l7policy.enabled
}
if l7policy.redirect_pool:

View File

@ -106,6 +106,9 @@ bind {{ lb_vip_address }}:{{ listener.protocol_port }} {{
{% 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(
l7policy) }}
{% endif %}
{% endmacro %}

View File

@ -194,29 +194,43 @@ def sanitize_l7policy_api_args(l7policy, create=False):
raise exceptions.InvalidL7PolicyArgs(
msg='redirect_pool_id or redirect_pool must not be None')
l7policy.update({'redirect_url': None})
elif l7policy['action'] == constants.L7POLICY_ACTION_REDIRECT_PREFIX:
if not l7policy.get('redirect_prefix'):
raise exceptions.InvalidL7PolicyArgs(
msg='redirect_prefix must not be None')
else:
raise exceptions.InvalidL7PolicyAction(
action=l7policy['action'])
if ((l7policy.get('redirect_pool_id') or
l7policy.get('redirect_pool')) and l7policy.get('redirect_url')):
if ((l7policy.get('redirect_pool_id') or l7policy.get('redirect_pool')) and
(l7policy.get('redirect_url') or l7policy.get('redirect_prefix'))):
raise exceptions.InvalidL7PolicyArgs(
msg='Cannot specify redirect_pool_id and redirect_url '
'at the same time')
msg='Cannot specify redirect_pool_id and redirect_url or '
'redirect_prefix at the same time')
if l7policy.get('redirect_pool_id'):
l7policy.update({
'action': constants.L7POLICY_ACTION_REDIRECT_TO_POOL})
l7policy.update({'redirect_url': None})
l7policy.pop('redirect_pool', None)
l7policy.update({'redirect_prefix': 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})
if l7policy.get('redirect_url'):
url(l7policy['redirect_url'])
l7policy.update({
'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL})
l7policy.update({'redirect_pool_id': None})
l7policy.update({'redirect_prefix': None})
l7policy.pop('redirect_pool', None)
if l7policy.get('redirect_prefix'):
url(l7policy['redirect_prefix'])
l7policy.update({
'action': constants.L7POLICY_ACTION_REDIRECT_PREFIX})
l7policy.update({'redirect_pool_id': None})
l7policy.update({'redirect_url': None})
l7policy.pop('redirect_pool', None)
# If we are creating, we need an action at this point

View File

@ -0,0 +1,49 @@
#
# 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 action redirect prefix
Revision ID: 55874a4ceed6
Revises: 76aacf2e176c
Create Date: 2018-09-09 20:35:38.780054
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy import sql
# revision identifiers, used by Alembic.
revision = '55874a4ceed6'
down_revision = '76aacf2e176c'
def upgrade():
# Add collumn redirect_prefix
op.add_column(
u'l7policy',
sa.Column(u'redirect_prefix', sa.String(255), nullable=True)
)
insert_table = sql.table(
u'l7policy_action',
sql.column(u'name', sa.String),
sql.column(u'description', sa.String)
)
op.bulk_insert(
insert_table,
[
{'name': 'REDIRECT_PREFIX'}
]
)

View File

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

View File

@ -1589,12 +1589,19 @@ class L7PolicyRepository(BaseRepository):
if l7policy.action == consts.L7POLICY_ACTION_REJECT:
model_kwargs.update(redirect_url=None)
model_kwargs.update(redirect_pool_id=None)
model_kwargs.update(redirect_prefix=None)
elif (l7policy.action ==
consts.L7POLICY_ACTION_REDIRECT_TO_URL):
model_kwargs.update(redirect_pool_id=None)
model_kwargs.update(redirect_prefix=None)
elif (l7policy.action ==
consts.L7POLICY_ACTION_REDIRECT_TO_POOL):
model_kwargs.update(redirect_url=None)
model_kwargs.update(redirect_prefix=None)
elif (l7policy.action ==
consts.L7POLICY_ACTION_REDIRECT_PREFIX):
model_kwargs.update(redirect_url=None)
model_kwargs.update(redirect_pool_id=None)
l7policy_db.update(model_kwargs)

View File

@ -684,6 +684,7 @@ class TestLoadBalancerGraph(base.BaseAPITest):
'name': None,
'description': None,
'redirect_url': None,
'redirect_prefix': None,
'l7rules': []
}
expected_l7policy.update(create_l7policy)

View File

@ -2256,6 +2256,7 @@ class TestLoadBalancerGraph(base.BaseAPITest):
'name': '',
'description': '',
'redirect_url': None,
'redirect_prefix': None,
'rules': [],
'project_id': self._project_id,
'provisioning_status': constants.PENDING_CREATE,

View File

@ -301,6 +301,7 @@ class SampleDriverDataModels(object):
'action': 'go',
'redirect_pool_id': self.pool1_id,
'redirect_url': '/index.html',
'redirect_prefix': 'https://example.com/',
'position': 1,
'listener': None,
'redirect_pool': None,
@ -323,16 +324,19 @@ class SampleDriverDataModels(object):
self.db_l7policies = [self.db_l7policy1, self.db_l7policy2]
self.provider_l7policy1_dict = {'action': 'go',
'admin_state_up': True,
'description': 'L7policy 1',
'l7policy_id': self.l7policy1_id,
'listener_id': self.listener1_id,
'name': 'l7policy_1',
'position': 1,
'redirect_pool_id': self.pool1_id,
'redirect_url': '/index.html',
'rules': self.provider_l7rules_dicts}
self.provider_l7policy1_dict = {
'action': 'go',
'admin_state_up': True,
'description': 'L7policy 1',
'l7policy_id': self.l7policy1_id,
'listener_id': self.listener1_id,
'name': 'l7policy_1',
'position': 1,
'redirect_pool_id': self.pool1_id,
'redirect_url': '/index.html',
'redirect_prefix': 'https://example.com/',
'rules': self.provider_l7rules_dicts
}
self.provider_l7policy2_dict = copy.deepcopy(
self.provider_l7policy1_dict)

View File

@ -623,6 +623,12 @@ class TestHaproxyCfg(base.TestCase):
".example.com\n"
" http-request deny if sample_l7rule_id_4 "
"sample_l7rule_id_5\n"
" acl sample_l7rule_id_2 req.hdr(Some-header) -m sub "
"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 "
"!sample_l7rule_id_2 sample_l7rule_id_3\n"
" default_backend sample_pool_id_1\n"
" timeout client 50000\n\n").format(
maxconn=constants.HAPROXY_MAX_MAXCONN)

View File

@ -192,6 +192,7 @@ RET_L7POLICY_1 = {
'action': constants.L7POLICY_ACTION_REDIRECT_TO_POOL,
'redirect_pool': RET_POOL_2,
'redirect_url': None,
'redirect_prefix': None,
'enabled': True,
'l7rules': [RET_L7RULE_1]}
@ -200,6 +201,7 @@ RET_L7POLICY_2 = {
'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]}
@ -208,6 +210,7 @@ RET_L7POLICY_3 = {
'action': constants.L7POLICY_ACTION_REJECT,
'redirect_pool': None,
'redirect_url': None,
'redirect_prefix': None,
'enabled': True,
'l7rules': [RET_L7RULE_4, RET_L7RULE_5]}
@ -216,6 +219,7 @@ RET_L7POLICY_4 = {
'action': constants.L7POLICY_ACTION_REJECT,
'redirect_pool': None,
'redirect_url': None,
'redirect_prefix': None,
'enabled': True,
'l7rules': []}
@ -224,6 +228,7 @@ RET_L7POLICY_5 = {
'action': constants.L7POLICY_ACTION_REJECT,
'redirect_pool': None,
'redirect_url': None,
'redirect_prefix': None,
'enabled': False,
'l7rules': [RET_L7RULE_5]}
@ -232,9 +237,19 @@ RET_L7POLICY_6 = {
'action': constants.L7POLICY_ACTION_REJECT,
'redirect_pool': None,
'redirect_url': None,
'redirect_prefix': None,
'enabled': True,
'l7rules': []}
RET_L7POLICY_7 = {
'id': 'sample_l7policy_id_7',
'action': constants.L7POLICY_ACTION_REDIRECT_PREFIX,
'redirect_pool': None,
'redirect_url': None,
'redirect_prefix': 'https://example.com',
'enabled': True,
'l7rules': [RET_L7RULE_2, RET_L7RULE_3]}
RET_LISTENER = {
'id': 'sample_listener_id_1',
'protocol_port': '80',
@ -267,7 +282,8 @@ RET_LISTENER_L7 = {
'topology': 'SINGLE',
'pools': [RET_POOL_1, RET_POOL_2],
'l7policies': [RET_L7POLICY_1, RET_L7POLICY_2, RET_L7POLICY_3,
RET_L7POLICY_4, RET_L7POLICY_5, RET_L7POLICY_6],
RET_L7POLICY_4, RET_L7POLICY_5, RET_L7POLICY_6,
RET_L7POLICY_7],
'enabled': True,
'insert_headers': {},
'timeout_client_data': 50000,
@ -527,7 +543,8 @@ def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
sample_l7policy_tuple('sample_l7policy_id_3', sample_policy=3),
sample_l7policy_tuple('sample_l7policy_id_4', sample_policy=4),
sample_l7policy_tuple('sample_l7policy_id_5', sample_policy=5),
sample_l7policy_tuple('sample_l7policy_id_6', sample_policy=6)]
sample_l7policy_tuple('sample_l7policy_id_6', sample_policy=6),
sample_l7policy_tuple('sample_l7policy_id_7', sample_policy=7)]
else:
pools = [
sample_pool_tuple(
@ -733,10 +750,12 @@ def sample_health_monitor_tuple(proto='HTTP', sample_hm=1):
def sample_l7policy_tuple(id,
action=constants.L7POLICY_ACTION_REJECT,
redirect_pool=None, redirect_url=None,
redirect_prefix=None,
enabled=True, sample_policy=1):
in_l7policy = collections.namedtuple('l7policy',
'id, action, redirect_pool, '
'redirect_url, l7rules, enabled')
'redirect_url, redirect_prefix, '
'l7rules, enabled')
l7rules = []
if sample_policy == 1:
action = constants.L7POLICY_ACTION_REDIRECT_TO_POOL
@ -760,11 +779,17 @@ def sample_l7policy_tuple(id,
elif sample_policy == 6:
action = constants.L7POLICY_ACTION_REJECT
l7rules = [sample_l7rule_tuple('sample_l7rule_id_6', sample_rule=6)]
elif sample_policy == 7:
action = constants.L7POLICY_ACTION_REDIRECT_PREFIX
redirect_prefix = 'https://example.com'
l7rules = [sample_l7rule_tuple('sample_l7rule_id_2', sample_rule=2),
sample_l7rule_tuple('sample_l7rule_id_3', sample_rule=3)]
return in_l7policy(
id=id,
action=action,
redirect_pool=redirect_pool,
redirect_url=redirect_url,
redirect_prefix=redirect_prefix,
l7rules=l7rules,
enabled=enabled)

View File

@ -0,0 +1,3 @@
---
features:
- Support REDIRECT_PREFIX action for L7Policy