Align Octavia API to n-lbaasv2 for L7Policy

GET all - /v2.0/lbaas/l7policies/<l7policy-id>
GET one - /v2.0/lbaas/l7policies/<l7policy-id>
POST - /v2.0/lbaas/l7policies {<body>}
PUT - /v2.0/lbaas/l7policies/<l7policy-id> {<body>}
DELETE - /v2.0/lbaas/l7policies/<l7policy-id>

Co-Authored-By: Nakul Dahiwade <nakul.dahiwade@intel.com>
Co-Authored-By: Adam Harwell <flux.adam@gmail.com>

Partially-Implements: #1616655

Change-Id: I91baf79df16d4a1eefd151ed87ec871b57ac6ef8
This commit is contained in:
Sindhu Devale 2016-12-02 19:42:36 +00:00 committed by Adam Harwell
parent 53ada8f74a
commit c9daa3ff6e
20 changed files with 1253 additions and 45 deletions

View File

@ -16,6 +16,7 @@ from wsme import types as wtypes
from wsmeext import pecan as wsme_pecan
from octavia.api.v2.controllers import base
from octavia.api.v2.controllers import l7policy
from octavia.api.v2.controllers import listener
from octavia.api.v2.controllers import load_balancer
from octavia.api.v2.controllers import pool
@ -25,6 +26,7 @@ class BaseV2Controller(base.BaseController):
loadbalancers = load_balancer.LoadBalancersController()
listeners = listener.ListenersController()
pools = pool.PoolsController()
l7policies = l7policy.L7PolicyController()
@wsme_pecan.wsexpose(wtypes.text)
def get(self):

View File

@ -0,0 +1,279 @@
# Copyright 2016 Blue Box, an IBM Company
#
# 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.
import logging
from oslo_config import cfg
from oslo_db import exception as odb_exceptions
from oslo_utils import excutils
import pecan
from wsme import types as wtypes
from wsmeext import pecan as wsme_pecan
from octavia.api.v1.controllers import l7rule
from octavia.api.v2.controllers import base
from octavia.api.v2.types import l7policy as l7policy_types
from octavia.common import constants
from octavia.common import data_models
from octavia.common import exceptions
from octavia.common import validate
from octavia.db import api as db_api
from octavia.db import prepare as db_prepare
from octavia.i18n import _LI
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
class L7PolicyController(base.BaseController):
def __init__(self):
super(L7PolicyController, self).__init__()
self.handler = self.handler.l7policy
@wsme_pecan.wsexpose(l7policy_types.L7PolicyRootResponse, wtypes.text)
def get(self, id):
"""Gets a single l7policy's details."""
context = pecan.request.context.get('octavia_context')
db_l7policy = self._get_db_l7policy(context.session, id)
result = self._convert_db_to_type(db_l7policy,
l7policy_types.L7PolicyResponse)
return l7policy_types.L7PolicyRootResponse(l7policy=result)
@wsme_pecan.wsexpose(l7policy_types.L7PoliciesRootResponse, wtypes.text,
wtypes.text)
def get_all(self, tenant_id=None, project_id=None):
"""Lists all l7policies of a listener."""
context = pecan.request.context.get('octavia_context')
if context.is_admin or CONF.auth_strategy == constants.NOAUTH:
if project_id or tenant_id:
project_id = {'project_id': project_id or tenant_id}
else:
project_id = {}
else:
project_id = {'project_id': context.project_id}
db_l7policies = self.repositories.l7policy.get_all(
context.session, **project_id)
result = self._convert_db_to_type(db_l7policies,
[l7policy_types.L7PolicyResponse])
return l7policy_types.L7PoliciesRootResponse(l7policies=result)
def _test_lb_and_listener_statuses(self, session, lb_id, listener_ids):
"""Verify load balancer is in a mutable state."""
if not self.repositories.test_and_set_lb_and_listeners_prov_status(
session, lb_id,
constants.PENDING_UPDATE, constants.PENDING_UPDATE,
listener_ids=listener_ids):
LOG.info(_LI("L7Policy cannot be created or modified because the "
"Load Balancer is in an immutable state"))
raise exceptions.ImmutableObject(resource='Load Balancer',
id=lb_id)
def _get_listener_and_loadbalancer_id(self, db_l7policy):
"""Get listener and loadbalancer ids from the l7policy db_model."""
load_balancer_id = db_l7policy.listener.load_balancer_id
listener_id = db_l7policy.listener_id
return load_balancer_id, listener_id
def _reset_lb_and_listener_statuses(self, session, lb_id, listener_id):
# Setting LB + listeners back to active because this should be a
# recoverable error
self.repositories.load_balancer.update(
session, lb_id,
provisioning_status=constants.ACTIVE)
self.repositories.listener.update(
session, listener_id,
provisioning_status=constants.ACTIVE)
def _validate_create_l7policy(self, lock_session, l7policy_dict):
try:
return self.repositories.l7policy.create(lock_session,
**l7policy_dict)
except odb_exceptions.DBDuplicateEntry as de:
if ['id'] == de.columns:
raise exceptions.IDAlreadyExists()
except odb_exceptions.DBError:
# TODO(blogan): will have to do separate validation protocol
# before creation or update since the exception messages
# do not give any information as to what constraint failed
raise exceptions.InvalidOption(value='', option='')
def _send_l7policy_to_handler(self, session, db_l7policy, lb_id):
try:
LOG.info(_LI("Sending Creation of L7Policy %s to handler"),
db_l7policy.id)
self.handler.create(db_l7policy)
except Exception:
with excutils.save_and_reraise_exception(
reraise=False), db_api.get_lock_session() as lock_session:
self._reset_lb_and_listener_statuses(
lock_session, lb_id=lb_id,
listener_id=db_l7policy.listener_id)
# L7Policy now goes to ERROR
self.repositories.l7policy.update(
lock_session, db_l7policy.id,
provisioning_status=constants.ERROR)
db_l7policy = self._get_db_l7policy(session, db_l7policy.id)
result = self._convert_db_to_type(db_l7policy,
l7policy_types.L7PolicyResponse)
return l7policy_types.L7PolicyRootResponse(l7policy=result)
@wsme_pecan.wsexpose(l7policy_types.L7PolicyRootResponse,
body=l7policy_types.L7PolicyRootPOST, status_code=201)
def post(self, l7policy_):
"""Creates a l7policy on a listener."""
l7policy = l7policy_.l7policy
context = pecan.request.context.get('octavia_context')
# l7policy_dict = validate.sanitize_l7policy_api_args(
# l7policy.to_dict(render_unsets=True), create=True)
if l7policy.redirect_pool_id:
self._get_db_pool(
context.session, l7policy.redirect_pool_id)
# Make sure any pool specified by redirect_pool_id exists
listener_id = l7policy.listener_id
listener = self._get_db_listener(
context.session, listener_id)
load_balancer_id = listener.load_balancer_id
l7policy.project_id = listener.project_id
lock_session = db_api.get_session(autocommit=False)
if self.repositories.check_quota_met(
context.session,
lock_session,
data_models.L7Policy,
l7policy.project_id):
lock_session.rollback()
raise exceptions.QuotaException
l7policy_dict = db_prepare.create_l7policy(
l7policy.to_dict(render_unsets=True),
load_balancer_id, listener_id)
try:
self._test_lb_and_listener_statuses(
lock_session, lb_id=load_balancer_id,
listener_ids=[listener_id])
db_l7policy = self._validate_create_l7policy(
lock_session, l7policy_dict)
lock_session.commit()
except Exception:
with excutils.save_and_reraise_exception():
lock_session.rollback()
return self._send_l7policy_to_handler(context.session, db_l7policy,
lb_id=load_balancer_id)
@wsme_pecan.wsexpose(l7policy_types.L7PolicyRootResponse,
wtypes.text, body=l7policy_types.L7PolicyRootPUT,
status_code=200)
def put(self, id, l7policy_):
"""Updates a l7policy."""
l7policy = l7policy_.l7policy
l7policy_dict = validate.sanitize_l7policy_api_args(
l7policy.to_dict(render_unsets=False))
# Reset renamed attributes
for attr, val in l7policy_types.L7PolicyPUT._type_to_model_map.items():
if val in l7policy_dict:
l7policy_dict[attr] = l7policy_dict.pop(val)
sanitized_l7policy = l7policy_types.L7PolicyPUT(**l7policy_dict)
context = pecan.request.context.get('octavia_context')
# Make sure any specified redirect_pool_id exists
if l7policy_dict.get('redirect_pool_id'):
self._get_db_pool(
context.session, l7policy_dict['redirect_pool_id'])
db_l7policy = self._get_db_l7policy(context.session, id)
load_balancer_id, listener_id = self._get_listener_and_loadbalancer_id(
db_l7policy)
self._test_lb_and_listener_statuses(context.session,
lb_id=load_balancer_id,
listener_ids=[listener_id])
self.repositories.l7policy.update(
context.session, db_l7policy.id,
provisioning_status=constants.PENDING_UPDATE)
try:
LOG.info(_LI("Sending Update of L7Policy %s to handler"), id)
self.handler.update(
db_l7policy, sanitized_l7policy)
except Exception:
with excutils.save_and_reraise_exception(
reraise=False), db_api.get_lock_session() as lock_session:
self._reset_lb_and_listener_statuses(
lock_session, lb_id=load_balancer_id,
listener_id=db_l7policy.listener_id)
# L7Policy now goes to ERROR
self.repositories.l7policy.update(
lock_session, db_l7policy.id,
provisioning_status=constants.ERROR)
db_l7policy = self._get_db_l7policy(context.session, id)
result = self._convert_db_to_type(db_l7policy,
l7policy_types.L7PolicyResponse)
return l7policy_types.L7PolicyRootResponse(l7policy=result)
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
def delete(self, id):
"""Deletes a l7policy."""
context = pecan.request.context.get('octavia_context')
db_l7policy = self._get_db_l7policy(context.session, id)
load_balancer_id, listener_id = self._get_listener_and_loadbalancer_id(
db_l7policy)
self._test_lb_and_listener_statuses(context.session,
lb_id=load_balancer_id,
listener_ids=[listener_id])
self.repositories.l7policy.update(
context.session, db_l7policy.id,
provisioning_status=constants.PENDING_DELETE)
try:
LOG.info(_LI("Sending Deletion of L7Policy %s to handler"),
db_l7policy.id)
self.handler.delete(db_l7policy)
except Exception:
with excutils.save_and_reraise_exception(
reraise=False), db_api.get_lock_session() as lock_session:
self._reset_lb_and_listener_statuses(
lock_session, lb_id=load_balancer_id,
listener_id=db_l7policy.listener_id)
# L7Policy now goes to ERROR
self.repositories.l7policy.update(
lock_session, db_l7policy.id,
provisioning_status=constants.ERROR)
db_l7policy = self.repositories.l7policy.get(context.session, id=id)
result = self._convert_db_to_type(db_l7policy,
l7policy_types.L7PolicyResponse)
return l7policy_types.L7PolicyRootResponse(l7policy=result)
@pecan.expose()
def _lookup(self, l7policy_id, *remainder):
"""Overridden pecan _lookup method for custom routing.
Verifies that the l7policy passed in the url exists, and if so decides
which controller, if any, should control be passed.
"""
context = pecan.request.context.get('octavia_context')
db_l7policy = self._get_db_l7policy(context.session, l7policy_id)
load_balancer_id, listener_id = self._get_listener_and_loadbalancer_id(
db_l7policy)
if l7policy_id and len(remainder) and remainder[0] == 'l7rules':
remainder = remainder[1:]
db_l7policy = self.repositories.l7policy.get(
context.session, id=l7policy_id)
if not db_l7policy:
LOG.info(_LI("L7Policy %s not found."), l7policy_id)
raise exceptions.NotFound(
resource=data_models.L7Policy._name(), id=l7policy_id)
return l7rule.L7RuleController(
load_balancer_id=load_balancer_id,
listener_id=listener_id,
l7policy_id=db_l7policy.id), remainder

View File

@ -0,0 +1,112 @@
# Copyright 2016 Blue Box, an IBM Company
#
# 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.
from wsme import types as wtypes
from octavia.api.common import types
from octavia.common import constants
class BaseL7PolicyType(types.BaseType):
_type_to_model_map = {'admin_state_up': 'enabled'}
class MinimalL7Rule(types.BaseType):
id = wtypes.wsattr(wtypes.UuidType())
class L7PolicyResponse(BaseL7PolicyType):
"""Defines which attributes are to be shown on any response."""
id = wtypes.wsattr(wtypes.UuidType())
name = wtypes.wsattr(wtypes.StringType())
description = wtypes.wsattr(wtypes.StringType())
provisioning_status = wtypes.wsattr(wtypes.StringType())
operating_status = wtypes.wsattr(wtypes.StringType())
admin_state_up = wtypes.wsattr(bool)
# TODO(johnsom) Remove after deprecation (R series)
project_id = wtypes.wsattr(wtypes.StringType())
# TODO(johnsom) Remove after deprecation (R series)
tenant_id = wtypes.wsattr(wtypes.StringType())
action = wtypes.wsattr(wtypes.StringType())
listener_id = wtypes.wsattr(wtypes.UuidType())
redirect_pool_id = wtypes.wsattr(wtypes.UuidType())
redirect_url = wtypes.wsattr(wtypes.StringType())
position = wtypes.wsattr(wtypes.IntegerType())
rules = wtypes.wsattr([MinimalL7Rule])
created_at = wtypes.wsattr(wtypes.datetime.datetime)
updated_at = wtypes.wsattr(wtypes.datetime.datetime)
@classmethod
def from_data_model(cls, data_model, children=False):
policy = super(L7PolicyResponse, cls).from_data_model(
data_model, children=children)
policy.tenant_id = data_model.project_id
if not policy.name:
policy.name = ""
if not policy.description:
policy.description = ""
policy.rules = [
MinimalL7Rule.from_data_model(i) for i in data_model.l7rules]
return policy
class L7PolicyRootResponse(types.BaseType):
l7policy = wtypes.wsattr(L7PolicyResponse)
class L7PoliciesRootResponse(types.BaseType):
l7policies = wtypes.wsattr([L7PolicyResponse])
class L7PolicyPOST(BaseL7PolicyType):
"""Defines mandatory and optional attributes of a POST request."""
name = wtypes.wsattr(wtypes.StringType(max_length=255))
description = wtypes.wsattr(wtypes.StringType(max_length=255))
admin_state_up = wtypes.wsattr(bool, default=True)
# TODO(johnsom) Remove after deprecation (R series)
project_id = wtypes.wsattr(wtypes.StringType(max_length=36))
# TODO(johnsom) Remove after deprecation (R series)
tenant_id = wtypes.wsattr(wtypes.StringType(max_length=36))
action = wtypes.wsattr(
wtypes.Enum(str, *constants.SUPPORTED_L7POLICY_ACTIONS),
mandatory=True)
redirect_pool_id = wtypes.wsattr(wtypes.UuidType())
redirect_url = wtypes.wsattr(types.URLType())
position = wtypes.wsattr(wtypes.IntegerType(
minimum=constants.MIN_POLICY_POSITION,
maximum=constants.MAX_POLICY_POSITION),
default=constants.MAX_POLICY_POSITION)
listener_id = wtypes.wsattr(wtypes.UuidType(), mandatory=True)
class L7PolicyRootPOST(types.BaseType):
l7policy = wtypes.wsattr(L7PolicyPOST)
class L7PolicyPUT(BaseL7PolicyType):
"""Defines attributes that are acceptable of a PUT request."""
name = wtypes.wsattr(wtypes.StringType(max_length=255))
description = wtypes.wsattr(wtypes.StringType(max_length=255))
admin_state_up = wtypes.wsattr(bool)
action = wtypes.wsattr(
wtypes.Enum(str, *constants.SUPPORTED_L7POLICY_ACTIONS))
redirect_pool_id = wtypes.wsattr(wtypes.UuidType())
redirect_url = wtypes.wsattr(types.URLType())
position = wtypes.wsattr(wtypes.IntegerType(
minimum=constants.MIN_POLICY_POSITION,
maximum=constants.MAX_POLICY_POSITION))
class L7PolicyRootPUT(types.BaseType):
l7policy = wtypes.wsattr(L7PolicyPUT)

View File

@ -85,7 +85,7 @@ class ListenerResponse(BaseListenerType):
if not listener.default_pool:
del listener.default_pool
del listener.default_pool_id
if not listener.l7policies or len(listener.l7policies) <= 0:
if not listener.l7policies:
del listener.l7policies
return listener

View File

@ -51,6 +51,14 @@ class MinimalListener(types.BaseType):
id = wtypes.wsattr(wtypes.UuidType())
class MinimalMember(types.BaseType):
id = wtypes.wsattr(wtypes.UuidType())
class MinimalHealthmonitor(types.BaseType):
id = wtypes.wsattr(wtypes.UuidType())
class PoolResponse(BasePoolType):
"""Defines which attributes are to be shown on any response."""
id = wtypes.wsattr(wtypes.UuidType())
@ -70,9 +78,8 @@ class PoolResponse(BasePoolType):
listeners = wtypes.wsattr([MinimalListener])
created_at = wtypes.wsattr(wtypes.datetime.datetime)
updated_at = wtypes.wsattr(wtypes.datetime.datetime)
health_monitor = wtypes.wsattr(health_monitor.HealthMonitorResponse)
health_monitor_id = wtypes.wsattr(wtypes.UuidType())
members = wtypes.wsattr([member.MemberResponse])
members = wtypes.wsattr([MinimalMember])
@classmethod
def from_data_model(cls, data_model, children=False):
@ -84,32 +91,15 @@ class PoolResponse(BasePoolType):
SessionPersistenceResponse.from_data_model(
data_model.session_persistence))
if data_model.load_balancer:
pool.loadbalancers = (
[MinimalLoadBalancer.from_data_model(
data_model.load_balancer)])
if data_model.listeners:
pool.listeners = (
[MinimalListener.from_data_model(i)
for i in data_model.listeners])
pool.loadbalancers = [
MinimalLoadBalancer.from_data_model(data_model.load_balancer)]
else:
pool.listeners = []
if not children:
# NOTE(blogan): do not show members or health_monitor if the
# request does not want to see children
del pool.members
del pool.health_monitor
return pool
pool.loadbalancers = []
pool.listeners = [
MinimalListener.from_data_model(i) for i in data_model.listeners]
pool.members = [
member.MemberResponse.from_data_model(member_dm, children=children)
for member_dm in data_model.members
]
if data_model.health_monitor:
pool.health_monitor = (
health_monitor.HealthMonitorResponse.from_data_model(
data_model.health_monitor, children=children))
pool.health_monitor_id = pool.health_monitor.id
if not pool.health_monitor:
del pool.health_monitor
MinimalMember.from_data_model(i) for i in data_model.members]
return pool

View File

@ -119,6 +119,7 @@ SUPPORTED_L7POLICY_ACTIONS = (L7POLICY_ACTION_REJECT,
L7POLICY_ACTION_REDIRECT_TO_URL,
L7POLICY_ACTION_REDIRECT_TO_POOL)
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
# to be larger than any existing rule position numbers which will

View File

@ -547,7 +547,9 @@ class L7Policy(BaseDataModel):
def __init__(self, id=None, name=None, description=None, listener_id=None,
action=None, redirect_pool_id=None, redirect_url=None,
position=None, listener=None, redirect_pool=None,
enabled=None, l7rules=None, provisioning_status=None):
enabled=None, l7rules=None, provisioning_status=None,
operating_status=None, project_id=None, created_at=None,
updated_at=None):
self.id = id
self.name = name
self.description = description
@ -561,6 +563,10 @@ class L7Policy(BaseDataModel):
self.enabled = enabled
self.l7rules = l7rules or []
self.provisioning_status = provisioning_status
self.operating_status = operating_status
self.project_id = project_id
self.created_at = created_at
self.updated_at = updated_at
def _conditionally_remove_pool_links(self, pool):
"""Removes links to the given pool from parent objects.

View File

@ -1726,9 +1726,12 @@ class MarkL7PolicyActiveInDB(BaseDatabaseTask):
LOG.debug("Mark ACTIVE in DB for l7policy id: %s",
l7policy.id)
op_status = constants.ONLINE if l7policy.enabled else constants.OFFLINE
self.l7policy_repo.update(db_apis.get_session(),
l7policy.id,
provisioning_status=constants.ACTIVE)
provisioning_status=constants.ACTIVE,
operating_status=op_status)
def revert(self, l7policy, *args, **kwargs):
"""Mark the l7policy as broken

View File

@ -0,0 +1,96 @@
# Copyright 2017 GoDaddy
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""modernize_l7policy_fields
Revision ID: 034b2dc2f3e0
Revises: fac584114642
Create Date: 2017-04-01 05:44:43.400535
"""
from alembic import op
import sqlalchemy as sa
from octavia.common import constants
# revision identifiers, used by Alembic.
revision = '034b2dc2f3e0'
down_revision = 'fac584114642'
def upgrade():
# Add timing data
op.add_column(
u'l7policy',
sa.Column(u'created_at', sa.DateTime(), nullable=True)
)
op.add_column(
u'l7policy',
sa.Column(u'updated_at', sa.DateTime(), nullable=True)
)
# Add project_id
op.add_column(
u'l7policy',
sa.Column(u'project_id', sa.String(36), nullable=True)
)
# Add new operating_status column, setting existing rows to ONLINE
op.add_column(
u'l7policy',
sa.Column(u'operating_status', sa.String(16),
nullable=False, server_default=constants.ONLINE)
)
# Remove the default, as we don't actually want one
op.alter_column(u'l7policy', u'operating_status',
existing_type=sa.String(16), server_default=None)
# Add the foreign key for operating_status_name
op.create_foreign_key(
u'fk_l7policy_operating_status_name', u'l7policy',
u'operating_status', [u'operating_status'], [u'name']
)
# provisioning_status was mistakenly added as nullable, the fix is similar
op.alter_column(u'l7policy', u'provisioning_status', nullable=False,
existing_type=sa.String(16),
server_default=constants.ACTIVE)
op.alter_column(u'l7policy', u'provisioning_status',
existing_type=sa.String(16), server_default=None)
# Fix the rest of these that were also mistakenly set as nullable in:
# 9b5473976d6d_add_provisioning_status_to_objects.py
op.alter_column(u'health_monitor', u'provisioning_status', nullable=False,
existing_type=sa.String(16),
server_default=constants.ACTIVE)
op.alter_column(u'health_monitor', u'provisioning_status',
existing_type=sa.String(16), server_default=None)
op.alter_column(u'member', u'provisioning_status', nullable=False,
existing_type=sa.String(16),
server_default=constants.ACTIVE)
op.alter_column(u'member', u'provisioning_status',
existing_type=sa.String(16), server_default=None)
op.alter_column(u'pool', u'provisioning_status', nullable=False,
existing_type=sa.String(16),
server_default=constants.ACTIVE)
op.alter_column(u'pool', u'provisioning_status',
existing_type=sa.String(16), server_default=None)
op.alter_column(u'l7rule', u'provisioning_status', nullable=False,
existing_type=sa.String(16),
server_default=constants.ACTIVE)
op.alter_column(u'l7rule', u'provisioning_status',
existing_type=sa.String(16), server_default=None)

View File

@ -530,7 +530,8 @@ class L7Rule(base_models.BASE, base_models.IdMixin):
nullable=True)
class L7Policy(base_models.BASE, base_models.IdMixin, base_models.NameMixin):
class L7Policy(base_models.BASE, base_models.IdMixin, base_models.ProjectMixin,
models.TimestampMixin, base_models.NameMixin):
__data_model__ = data_models.L7Policy
@ -572,7 +573,12 @@ class L7Policy(base_models.BASE, base_models.IdMixin, base_models.NameMixin):
sa.String(16),
sa.ForeignKey("provisioning_status.name",
name="fk_l7policy_provisioning_status_name"),
nullable=True)
nullable=False)
operating_status = sa.Column(
sa.String(16),
sa.ForeignKey("operating_status.name",
name="fk_l7policy_operating_status_name"),
nullable=False)
class Quotas(base_models.BASE):

View File

@ -103,6 +103,8 @@ def create_listener(listener_dict, lb_id):
def create_l7policy(l7policy_dict, lb_id, listener_id):
l7policy_dict = validate.sanitize_l7policy_api_args(l7policy_dict,
create=True)
l7policy_dict['provisioning_status'] = constants.PENDING_CREATE
l7policy_dict['operating_status'] = constants.OFFLINE
if not l7policy_dict.get('id'):
l7policy_dict['id'] = uuidutils.generate_uuid()
l7policy_dict['listener_id'] = listener_id

View File

@ -1194,8 +1194,9 @@ class L7PolicyRepository(BaseRepository):
l7policy_db = listener.l7policies.pop(l7policy_db.position - 1)
listener.l7policies.insert(position - 1, l7policy_db)
listener.l7policies.reorder()
session.flush()
return self.get(session, id=l7policy.id)
return self.get(session, id=id)
def create(self, session, **model_kwargs):
with session.begin(subtransactions=True):
@ -1233,6 +1234,8 @@ class L7PolicyRepository(BaseRepository):
listener.l7policies.insert(position - 1, l7policy_db)
listener.l7policies.reorder()
session.flush()
l7policy.updated_at = None
return self.get(session, id=l7policy.id)
def delete(self, session, id, **filters):

View File

@ -174,7 +174,7 @@ class TestL7Policy(base.BaseAPITest):
listener_id=self.listener.get('id'))
body = {'id': l7policy.get('id'),
'action': constants.L7POLICY_ACTION_REJECT}
self.post(path, body, status=409, expect_errors=True)
self.post(path, body, status=409)
def test_bad_create(self):
l7policy = {'name': 'test1'}
@ -236,7 +236,7 @@ class TestL7Policy(base.BaseAPITest):
constants.L7POLICY_ACTION_REJECT)
new_l7policy = {'action': 'bad action'}
self.put(self.l7policy_path.format(l7policy_id=api_l7policy.get('id')),
new_l7policy, expect_errors=True)
new_l7policy, status=400)
def test_bad_update_redirect_to_pool(self):
api_l7policy = self.create_l7policy(
@ -245,7 +245,7 @@ class TestL7Policy(base.BaseAPITest):
new_l7policy = {'action': constants.L7POLICY_ACTION_REDIRECT_TO_POOL,
'redirect_pool_id': uuidutils.generate_uuid()}
self.put(self.l7policy_path.format(l7policy_id=api_l7policy.get('id')),
new_l7policy, expect_errors=True)
new_l7policy, status=404)
def test_bad_update_redirect_to_url(self):
api_l7policy = self.create_l7policy(
@ -254,7 +254,7 @@ class TestL7Policy(base.BaseAPITest):
new_l7policy = {'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
'redirect_url': 'bad url'}
self.put(self.l7policy_path.format(l7policy_id=api_l7policy.get('id')),
new_l7policy, expect_errors=True)
new_l7policy, status=400)
def test_update_with_bad_handler(self):
api_l7policy = self.create_l7policy(

View File

@ -70,6 +70,7 @@ class BaseAPITest(base_db_test.OctaviaDBTestBase):
self.listener_stats_repo = repositories.ListenerStatisticsRepository()
self.pool_repo = repositories.PoolRepository()
self.member_repo = repositories.MemberRepository()
self.l7policy_repo = repositories.L7PolicyRepository()
self.amphora_repo = repositories.AmphoraRepository()
patcher = mock.patch('octavia.api.handlers.controller_simulator.'
'handler.SimulatedControllerHandler')
@ -280,6 +281,12 @@ class BaseAPITest(base_db_test.OctaviaDBTestBase):
self.listener_repo.update(db_api.get_session(), listener.id,
provisioning_status=listener_prov,
operating_status=op_status)
lb_l7policies = self.l7policy_repo.get_all(db_api.get_session(),
listener_id=listener.id)
for l7policy in lb_l7policies:
self.l7policy_repo.update(db_api.get_session(), l7policy.id,
provisioning_status=listener_prov,
operating_status=op_status)
lb_pools = self.pool_repo.get_all(db_api.get_session(),
load_balancer_id=lb_id)
for pool in lb_pools:
@ -373,16 +380,27 @@ class BaseAPITest(base_db_test.OctaviaDBTestBase):
self.assertEqual(operating_status,
api_member.get('operating_status'))
def assert_correct_l7policy_status(self, provisioning_status,
operating_status, l7policy_id):
api_l7policy = self.get(self.L7POLICY_PATH.format(
l7policy_id=l7policy_id)).json.get('l7policy')
self.assertEqual(provisioning_status,
api_l7policy.get('provisioning_status'))
self.assertEqual(operating_status,
api_l7policy.get('operating_status'))
def assert_correct_status(self, lb_id=None, listener_id=None, pool_id=None,
member_id=None,
member_id=None, l7policy_id=None,
lb_prov_status=constants.ACTIVE,
listener_prov_status=constants.ACTIVE,
pool_prov_status=constants.ACTIVE,
member_prov_status=constants.ACTIVE,
l7policy_prov_status=constants.ACTIVE,
lb_op_status=constants.ONLINE,
listener_op_status=constants.ONLINE,
pool_op_status=constants.ONLINE,
member_op_status=constants.ONLINE):
member_op_status=constants.ONLINE,
l7policy_op_status=constants.ONLINE):
if lb_id:
self.assert_correct_lb_status(lb_prov_status, lb_op_status, lb_id)
if listener_id:
@ -394,3 +412,6 @@ class BaseAPITest(base_db_test.OctaviaDBTestBase):
if member_id:
self.assert_correct_member_status(
member_prov_status, member_op_status, pool_id, member_id)
if l7policy_id:
self.assert_correct_l7policy_status(
l7policy_prov_status, l7policy_op_status, l7policy_id)

View File

@ -0,0 +1,518 @@
# Copyright 2016 Blue Box, an IBM Company
#
# 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.
import mock
from oslo_utils import uuidutils
from octavia.common import constants
import octavia.common.context
from octavia.tests.functional.api.v2 import base
class TestL7Policy(base.BaseAPITest):
root_tag = 'l7policy'
root_tag_list = 'l7policies'
root_tag_links = 'l7policies_links'
def setUp(self):
super(TestL7Policy, self).setUp()
self.lb = self.create_load_balancer(uuidutils.generate_uuid())
self.lb_id = self.lb.get('loadbalancer').get('id')
self.set_lb_status(self.lb_id)
self.listener = self.create_listener(
constants.PROTOCOL_HTTP, 80, lb_id=self.lb_id)
self.listener_id = self.listener.get('listener').get('id')
self.set_lb_status(self.lb_id)
self.pool = self.create_pool(
self.lb_id,
constants.PROTOCOL_HTTP,
constants.LB_ALGORITHM_ROUND_ROBIN)
self.pool_id = self.pool.get('pool').get('id')
self.set_lb_status(self.lb_id)
def test_get(self):
api_l7policy = self.create_l7policy(
self.listener_id,
constants.L7POLICY_ACTION_REJECT).get(self.root_tag)
response = self.get(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id'))).json.get(self.root_tag)
self.assertEqual(api_l7policy, response)
def test_bad_get(self):
self.get(self.L7POLICY_PATH.format(
l7policy_id=uuidutils.generate_uuid()), status=404)
def test_get_all(self):
api_l7policy = self.create_l7policy(self.listener_id,
constants.L7POLICY_ACTION_REJECT,
).get(self.root_tag)
self.set_lb_status(self.lb_id)
policies = self.get(self.L7POLICIES_PATH).json.get(self.root_tag_list)
self.assertIsInstance(policies, list)
self.assertEqual(1, len(policies))
self.assertEqual(api_l7policy.get('id'), policies[0].get('id'))
def test_get_all_admin(self):
project_id = uuidutils.generate_uuid()
lb1 = self.create_load_balancer(uuidutils.generate_uuid(), name='lb1',
project_id=project_id)
lb1_id = lb1.get('loadbalancer').get('id')
self.set_lb_status(lb1_id)
listener1 = self.create_listener(constants.PROTOCOL_HTTP, 80,
lb1_id)
listener1_id = listener1.get('listener').get('id')
self.set_lb_status(lb1_id)
pool1 = self.create_pool(lb1_id, constants.PROTOCOL_HTTP,
constants.LB_ALGORITHM_ROUND_ROBIN)
pool1_id = pool1.get('pool').get('id')
self.set_lb_status(lb1_id)
api_l7p_a = self.create_l7policy(
listener1_id,
constants.L7POLICY_ACTION_REJECT).get(self.root_tag)
self.set_lb_status(lb1_id)
api_l7p_b = self.create_l7policy(
listener1_id, constants.L7POLICY_ACTION_REDIRECT_TO_POOL,
position=2, redirect_pool_id=pool1_id).get(self.root_tag)
self.set_lb_status(lb1_id)
api_l7p_c = self.create_l7policy(
listener1_id, constants.L7POLICY_ACTION_REDIRECT_TO_URL,
position=3, redirect_url='http://localhost/').get(self.root_tag)
self.set_lb_status(lb1_id)
policies = self.get(self.L7POLICIES_PATH).json.get(self.root_tag_list)
self.assertEqual(3, len(policies))
policy_id_actions = [(p.get('id'), p.get('action')) for p in policies]
self.assertIn((api_l7p_a.get('id'), api_l7p_a.get('action')),
policy_id_actions)
self.assertIn((api_l7p_b.get('id'), api_l7p_b.get('action')),
policy_id_actions)
self.assertIn((api_l7p_c.get('id'), api_l7p_c.get('action')),
policy_id_actions)
def test_get_all_non_admin(self):
project_id = uuidutils.generate_uuid()
lb1 = self.create_load_balancer(uuidutils.generate_uuid(), name='lb1',
project_id=project_id)
lb1_id = lb1.get('loadbalancer').get('id')
self.set_lb_status(lb1_id)
listener1 = self.create_listener(constants.PROTOCOL_HTTP, 80,
lb1_id)
listener1_id = listener1.get('listener').get('id')
self.set_lb_status(lb1_id)
pool1 = self.create_pool(lb1_id, constants.PROTOCOL_HTTP,
constants.LB_ALGORITHM_ROUND_ROBIN)
pool1_id = pool1.get('pool').get('id')
self.set_lb_status(lb1_id)
self.create_l7policy(
listener1_id,
constants.L7POLICY_ACTION_REJECT).get(self.root_tag)
self.set_lb_status(lb1_id)
self.create_l7policy(
listener1_id, constants.L7POLICY_ACTION_REDIRECT_TO_POOL,
position=2, redirect_pool_id=pool1_id).get(self.root_tag)
self.set_lb_status(lb1_id)
api_l7p_c = self.create_l7policy(
self.listener_id, constants.L7POLICY_ACTION_REDIRECT_TO_URL,
redirect_url='http://localhost/').get(self.root_tag)
self.set_lb_status(lb1_id)
auth_strategy = self.conf.conf.get('auth_strategy')
self.conf.config(auth_strategy=constants.KEYSTONE)
with mock.patch.object(octavia.common.context.Context, 'project_id',
api_l7p_c.get('project_id')):
policies = self.get(
self.L7POLICIES_PATH).json.get(self.root_tag_list)
self.conf.config(auth_strategy=auth_strategy)
self.assertEqual(1, len(policies))
policy_id_actions = [(p.get('id'), p.get('action')) for p in policies]
self.assertIn((api_l7p_c.get('id'), api_l7p_c.get('action')),
policy_id_actions)
def test_get_by_project_id(self):
project1_id = uuidutils.generate_uuid()
project2_id = uuidutils.generate_uuid()
lb1 = self.create_load_balancer(uuidutils.generate_uuid(), name='lb1',
project_id=project1_id)
lb1_id = lb1.get('loadbalancer').get('id')
self.set_lb_status(lb1_id)
lb2 = self.create_load_balancer(uuidutils.generate_uuid(), name='lb2',
project_id=project2_id)
lb2_id = lb2.get('loadbalancer').get('id')
self.set_lb_status(lb2_id)
listener1 = self.create_listener(constants.PROTOCOL_HTTP, 80,
lb1_id)
listener1_id = listener1.get('listener').get('id')
self.set_lb_status(lb1_id)
listener2 = self.create_listener(constants.PROTOCOL_HTTP, 80,
lb2_id)
listener2_id = listener2.get('listener').get('id')
self.set_lb_status(lb2_id)
pool1 = self.create_pool(lb1_id, constants.PROTOCOL_HTTP,
constants.LB_ALGORITHM_ROUND_ROBIN)
pool1_id = pool1.get('pool').get('id')
self.set_lb_status(lb1_id)
api_l7p_a = self.create_l7policy(
listener1_id,
constants.L7POLICY_ACTION_REJECT).get(self.root_tag)
self.set_lb_status(lb1_id)
api_l7p_b = self.create_l7policy(
listener1_id, constants.L7POLICY_ACTION_REDIRECT_TO_POOL,
position=2, redirect_pool_id=pool1_id).get(self.root_tag)
self.set_lb_status(lb1_id)
api_l7p_c = self.create_l7policy(
listener2_id, constants.L7POLICY_ACTION_REDIRECT_TO_URL,
redirect_url='http://localhost/').get(self.root_tag)
self.set_lb_status(lb2_id)
policies = self.get(
self.L7POLICIES_PATH,
params={'project_id': project1_id}).json.get(self.root_tag_list)
self.assertEqual(2, len(policies))
policy_id_actions = [(p.get('id'), p.get('action')) for p in policies]
self.assertIn((api_l7p_a.get('id'), api_l7p_a.get('action')),
policy_id_actions)
self.assertIn((api_l7p_b.get('id'), api_l7p_b.get('action')),
policy_id_actions)
policies = self.get(
self.L7POLICIES_PATH,
params={'project_id': project2_id}).json.get(self.root_tag_list)
self.assertEqual(1, len(policies))
policy_id_actions = [(p.get('id'), p.get('action')) for p in policies]
self.assertIn((api_l7p_c.get('id'), api_l7p_c.get('action')),
policy_id_actions)
def test_empty_get_all(self):
response = self.get(self.L7POLICIES_PATH).json.get(self.root_tag_list)
self.assertIsInstance(response, list)
self.assertEqual(0, len(response))
def test_create_reject_policy(self):
api_l7policy = self.create_l7policy(self.listener_id,
constants.L7POLICY_ACTION_REJECT,
).get(self.root_tag)
self.assertEqual(constants.L7POLICY_ACTION_REJECT,
api_l7policy['action'])
self.assertEqual(1, api_l7policy['position'])
self.assertIsNone(api_l7policy['redirect_pool_id'])
self.assertIsNone(api_l7policy['redirect_url'])
self.assertTrue(api_l7policy['admin_state_up'])
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_create_redirect_to_pool(self):
api_l7policy = self.create_l7policy(
self.listener_id, constants.L7POLICY_ACTION_REDIRECT_TO_POOL,
redirect_pool_id=self.pool_id).get(self.root_tag)
self.assertEqual(constants.L7POLICY_ACTION_REDIRECT_TO_POOL,
api_l7policy['action'])
self.assertEqual(1, api_l7policy['position'])
self.assertEqual(self.pool_id, api_l7policy['redirect_pool_id'])
self.assertIsNone(api_l7policy['redirect_url'])
self.assertTrue(api_l7policy['admin_state_up'])
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_create_redirect_to_url(self):
api_l7policy = self.create_l7policy(
self.listener_id, constants.L7POLICY_ACTION_REDIRECT_TO_URL,
redirect_url='http://www.example.com').get(self.root_tag)
self.assertEqual(constants.L7POLICY_ACTION_REDIRECT_TO_URL,
api_l7policy['action'])
self.assertEqual(1, api_l7policy['position'])
self.assertIsNone(api_l7policy.get('redirect_pool_id'))
self.assertEqual('http://www.example.com',
api_l7policy['redirect_url'])
self.assertTrue(api_l7policy['admin_state_up'])
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'}
self.post(self.L7POLICIES_PATH, self._build_body(l7policy), status=400)
def test_bad_create_redirect_to_pool(self):
l7policy = {
'action': constants.L7POLICY_ACTION_REDIRECT_TO_POOL,
'listener_id': self.listener_id,
'redirect_pool_id': uuidutils.generate_uuid()}
self.post(self.L7POLICIES_PATH, self._build_body(l7policy), status=404)
def test_bad_create_redirect_to_url(self):
l7policy = {'listener_id': self.listener_id,
'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
'redirect_url': 'bad url'}
self.post(self.L7POLICIES_PATH, self._build_body(l7policy), status=400)
def test_create_with_bad_handler(self):
(self.handler_mock_bug_workaround.
l7policy.create.side_effect) = Exception
api_l7policy = self.create_l7policy(self.listener_id,
constants.L7POLICY_ACTION_REJECT,
).get(self.root_tag)
self.handler_mock_bug_workaround.l7policy.create.side_effect = None
self.assert_correct_status(
lb_id=self.lb_id, listener_id=self.listener_id,
l7policy_id=api_l7policy.get('id'),
l7policy_prov_status=constants.ERROR,
l7policy_op_status=constants.OFFLINE)
def test_update(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'}
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_REJECT,
response.get('action'))
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_UPDATE)
def test_bad_update(self):
api_l7policy = self.create_l7policy(self.listener_id,
constants.L7POLICY_ACTION_REJECT,
).get(self.root_tag)
new_l7policy = {'listener_id': self.listener_id,
'action': 'bad action'}
self.put(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id')),
self._build_body(new_l7policy), status=400)
def test_bad_update_redirect_to_pool(self):
api_l7policy = self.create_l7policy(self.listener_id,
constants.L7POLICY_ACTION_REJECT,
).get(self.root_tag)
new_l7policy = {
'listener_id': self.listener_id,
'action': constants.L7POLICY_ACTION_REDIRECT_TO_POOL,
'redirect_pool_id': uuidutils.generate_uuid()}
self.put(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id')),
self._build_body(new_l7policy), status=400)
def test_bad_update_redirect_to_url(self):
api_l7policy = self.create_l7policy(self.listener_id,
constants.L7POLICY_ACTION_REJECT,
).get(self.root_tag)
new_l7policy = {
'listener_id': self.listener_id,
'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
'redirect_url': 'bad url'}
self.put(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id')),
self._build_body(new_l7policy), status=400)
def test_update_with_bad_handler(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'}
(self.handler_mock_bug_workaround.
l7policy.update.side_effect) = Exception
self.put(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id')),
self._build_body(new_l7policy))
self.handler_mock_bug_workaround.l7policy.update.side_effect = None
self.assert_correct_status(
lb_id=self.lb_id, listener_id=self.listener_id,
l7policy_id=api_l7policy.get('id'),
l7policy_prov_status=constants.ERROR)
def test_update_redirect_to_pool_bad_pool_id(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 = {'redirect_pool_id': uuidutils.generate_uuid()}
self.put(self.L7POLICY_PATH.format(l7policy_id=api_l7policy.get('id')),
self._build_body(new_l7policy), status=404)
def test_update_redirect_to_pool_minimal(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 = {'redirect_pool_id': self.pool_id}
self.put(self.L7POLICY_PATH.format(l7policy_id=api_l7policy.get('id')),
self._build_body(new_l7policy))
def test_update_redirect_to_url_bad_url(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 = {'listener_id': self.listener_id,
'redirect_url': 'bad-url'}
self.put(self.L7POLICY_PATH.format(l7policy_id=api_l7policy.get('id')),
self._build_body(new_l7policy), status=400)
def test_update_redirect_to_url_minimal(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 = {'redirect_url': 'http://www.example.com/'}
self.put(self.L7POLICY_PATH.format(l7policy_id=api_l7policy.get('id')),
self._build_body(new_l7policy))
def test_delete(self):
api_l7policy = self.create_l7policy(
self.listener_id,
constants.L7POLICY_ACTION_REJECT).get(self.root_tag)
self.set_lb_status(self.lb_id)
# Set status to ACTIVE/ONLINE because set_lb_status did it in the db
api_l7policy['provisioning_status'] = constants.ACTIVE
api_l7policy['operating_status'] = constants.ONLINE
api_l7policy.pop('updated_at')
response = self.get(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id'))).json.get(self.root_tag)
response.pop('updated_at')
self.assertEqual(api_l7policy, response)
self.delete(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id')))
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_DELETE)
def test_bad_delete(self):
self.delete(self.L7POLICY_PATH.format(
l7policy_id=uuidutils.generate_uuid()), status=404)
def test_delete_with_bad_handler(self):
api_l7policy = self.create_l7policy(self.listener_id,
constants.L7POLICY_ACTION_REJECT,
).get(self.root_tag)
self.set_lb_status(self.lb_id)
# Set status to ACTIVE/ONLINE because set_lb_status did it in the db
api_l7policy['provisioning_status'] = constants.ACTIVE
api_l7policy['operating_status'] = constants.ONLINE
response = self.get(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id'))).json.get(self.root_tag)
self.assertIsNone(api_l7policy.pop('updated_at'))
self.assertIsNotNone(response.pop('updated_at'))
self.assertEqual(api_l7policy, response)
(self.handler_mock_bug_workaround.
l7policy.delete.side_effect) = Exception
self.delete(self.L7POLICY_PATH.format(
l7policy_id=api_l7policy.get('id')))
self.handler_mock_bug_workaround.l7policy.delete.side_effect = None
self.assert_correct_status(
lb_id=self.lb_id, listener_id=self.listener_id,
l7policy_id=api_l7policy.get('id'),
l7policy_prov_status=constants.ERROR)
def test_create_when_lb_pending_update(self):
self.create_l7policy(self.listener_id,
constants.L7POLICY_ACTION_REJECT,
)
self.set_lb_status(self.lb_id)
self.put(self.LB_PATH.format(lb_id=self.lb_id),
body={'loadbalancer': {'name': 'test_name_change'}})
new_l7policy = {
'listener_id': self.listener_id,
'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
'redirect_url': 'http://www.example.com'}
self.post(self.L7POLICIES_PATH, body=self._build_body(new_l7policy),
status=409)
def test_update_when_lb_pending_update(self):
l7policy = self.create_l7policy(self.listener_id,
constants.L7POLICY_ACTION_REJECT,
).get(self.root_tag)
self.set_lb_status(self.lb_id)
self.put(self.LB_PATH.format(lb_id=self.lb_id),
body={'loadbalancer': {'name': 'test_name_change'}})
new_l7policy = {'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
'redirect_url': 'http://www.example.com'}
self.put(self.L7POLICY_PATH.format(
l7policy_id=l7policy.get('id')),
body=self._build_body(new_l7policy), status=409)
def test_delete_when_lb_pending_update(self):
l7policy = self.create_l7policy(self.listener_id,
constants.L7POLICY_ACTION_REJECT,
).get(self.root_tag)
self.set_lb_status(self.lb_id)
self.put(self.LB_PATH.format(lb_id=self.lb_id),
body={'loadbalancer': {'name': 'test_name_change'}})
self.delete(self.L7POLICY_PATH.format(
l7policy_id=l7policy.get('id')),
status=409)
def test_create_when_lb_pending_delete(self):
self.delete(self.LB_PATH.format(lb_id=self.lb_id))
new_l7policy = {
'listener_id': self.listener_id,
'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
'redirect_url': 'http://www.example.com'}
self.post(self.L7POLICIES_PATH, body=self._build_body(new_l7policy),
status=409)
def test_update_when_lb_pending_delete(self):
l7policy = self.create_l7policy(self.listener_id,
constants.L7POLICY_ACTION_REJECT,
).get(self.root_tag)
self.set_lb_status(self.lb_id)
self.delete(self.LB_PATH.format(lb_id=self.lb_id))
new_l7policy = {
'action': constants.L7POLICY_ACTION_REDIRECT_TO_URL,
'redirect_url': 'http://www.example.com'}
self.put(self.L7POLICY_PATH.format(
l7policy_id=l7policy.get('id')),
body=self._build_body(new_l7policy), status=409)
def test_delete_when_lb_pending_delete(self):
l7policy = self.create_l7policy(self.listener_id,
constants.L7POLICY_ACTION_REJECT,
).get(self.root_tag)
self.set_lb_status(self.lb_id)
self.delete(self.LB_PATH.format(lb_id=self.lb_id))
self.delete(self.L7POLICY_PATH.format(
l7policy_id=l7policy.get('id')),
status=409)

View File

@ -172,8 +172,8 @@ class TestPool(base.BaseAPITest):
pools = self.get(
self.POOLS_PATH,
params={'project_id': project2_id}).json.get(self.root_tag_list)
pool_id_protocols = [(p.get('id'), p.get('protocol')) for p in pools]
self.assertEqual(1, len(pools))
pool_id_protocols = [(p.get('id'), p.get('protocol')) for p in pools]
self.assertIn((pool3.get('id'), pool3.get('protocol')),
pool_id_protocols)
@ -427,7 +427,6 @@ class TestPool(base.BaseAPITest):
self.delete(self.POOL_PATH.format(
pool_id=uuidutils.generate_uuid()), status=404)
@testtools.skip('Skip until complete v2 merge.')
def test_delete_with_l7policy(self):
api_pool = self.create_pool(
self.lb_id,

View File

@ -150,6 +150,8 @@ class ModelTestMixin(object):
'listener_id': listener_id,
'action': constants.L7POLICY_ACTION_REJECT,
'position': 1,
'provisioning_status': constants.PENDING_CREATE,
'operating_status': constants.OFFLINE,
'enabled': True}
kwargs.update(overrides)
return self._insert(session, models.L7Policy, kwargs)

View File

@ -366,7 +366,9 @@ class AllRepositoriesTest(base.OctaviaDBTestBase):
'action': constants.L7POLICY_ACTION_REDIRECT_TO_POOL,
'redirect_pool': redirect_pool, 'l7rules': [l7rule],
'redirect_pool_id': redirect_pool.get('id'),
'id': uuidutils.generate_uuid()}
'id': uuidutils.generate_uuid(),
'provisioning_status': constants.PENDING_CREATE,
'operating_status': constants.ONLINE}
l7rule['l7policy_id'] = l7policy.get('id')
listener = {'project_id': project_id, 'name': 'listener1',
'description': 'listener_description',
@ -3151,7 +3153,8 @@ class L7PolicyRepositoryTest(BaseRepositoryTest):
description='l7policy_description', listener_id=listener_id,
position=position, action=action,
redirect_pool_id=redirect_pool_id, redirect_url=redirect_url,
enabled=True)
operating_status=constants.ONLINE,
provisioning_status=constants.ACTIVE, enabled=True)
return l7policy
def create_l7rule(self, l7rule_id, l7policy_id,
@ -3223,6 +3226,8 @@ class L7PolicyRepositoryTest(BaseRepositoryTest):
l7policy = self.l7policy_repo.create(
self.session, listener_id=listener.id,
action=constants.L7POLICY_ACTION_REJECT,
operating_status=constants.ONLINE,
provisioning_status=constants.ACTIVE,
enabled=True)
new_l7policy = self.l7policy_repo.get(self.session, id=l7policy.id)
self.assertEqual(listener.id, new_l7policy.listener_id)
@ -3312,6 +3317,16 @@ class L7PolicyRepositoryTest(BaseRepositoryTest):
self.assertEqual(3, new_l7policy_a.position)
self.assertEqual(2, new_l7policy_b.position)
self.assertEqual(1, new_l7policy_c.position)
self.l7policy_repo.update(self.session, id=l7policy_c.id, position=1)
new_l7policy_a = self.l7policy_repo.get(self.session,
id=l7policy_a.id)
new_l7policy_b = self.l7policy_repo.get(self.session,
id=l7policy_b.id)
new_l7policy_c = self.l7policy_repo.get(self.session,
id=l7policy_c.id)
self.assertEqual(3, new_l7policy_a.position)
self.assertEqual(2, new_l7policy_b.position)
self.assertEqual(1, new_l7policy_c.position)
def test_delete_forcing_reorder(self):
listener = self.create_listener(uuidutils.generate_uuid(), 80)
@ -3516,7 +3531,8 @@ class L7RuleRepositoryTest(BaseRepositoryTest):
self.session, id=self.FAKE_UUID_1, name='l7policy_test',
description='l7policy_description', listener_id=self.listener.id,
position=1, action=constants.L7POLICY_ACTION_REJECT,
enabled=True)
operating_status=constants.ONLINE,
provisioning_status=constants.ACTIVE, enabled=True)
def create_l7rule(self, l7rule_id, l7policy_id,
type=constants.L7RULE_TYPE_PATH,
@ -3540,7 +3556,8 @@ class L7RuleRepositoryTest(BaseRepositoryTest):
self.session, id=uuidutils.generate_uuid(), name='l7policy_test',
description='l7policy_description', listener_id=self.listener.id,
position=1, action=constants.L7POLICY_ACTION_REJECT,
enabled=True)
operating_status=constants.ONLINE,
provisioning_status=constants.ACTIVE, enabled=True)
l7rule_a = self.create_l7rule(uuidutils.generate_uuid(), l7policy.id)
l7rule_b = self.create_l7rule(uuidutils.generate_uuid(), l7policy.id)
new_l7rule_a = self.l7rule_repo.get(self.session,

View File

@ -0,0 +1,150 @@
# Copyright 2016 Blue Box, an IBM Company
#
# 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.
from oslo_utils import uuidutils
from wsme import exc
from wsme.rest import json as wsme_json
from wsme import types as wsme_types
from octavia.api.v2.types import l7policy as l7policy_type
from octavia.common import constants
from octavia.tests.unit.api.common import base
class TestL7PolicyPOST(base.BaseTypesTest):
_type = l7policy_type.L7PolicyPOST
def setUp(self):
super(TestL7PolicyPOST, self).setUp()
self.listener_id = uuidutils.generate_uuid()
def test_l7policy(self):
body = {"listener_id": self.listener_id,
"action": constants.L7POLICY_ACTION_REJECT}
l7policy = wsme_json.fromjson(self._type, body)
self.assertEqual(self.listener_id, l7policy.listener_id)
self.assertEqual(constants.MAX_POLICY_POSITION, l7policy.position)
self.assertEqual(wsme_types.Unset, l7policy.redirect_url)
self.assertEqual(wsme_types.Unset, l7policy.redirect_pool_id)
self.assertTrue(l7policy.admin_state_up)
def test_action_mandatory(self):
body = {"listener_id": self.listener_id}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson, self._type,
body)
def test_listener_id_mandatory(self):
body = {"action": constants.L7POLICY_ACTION_REJECT}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson, self._type,
body)
def test_invalid_action(self):
body = {"listener_id": self.listener_id,
"action": "test"}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson, self._type,
body)
def test_with_redirect_url(self):
url = "http://www.example.com/"
body = {"listener_id": self.listener_id,
"action": constants.L7POLICY_ACTION_REDIRECT_TO_URL,
"redirect_url": url}
l7policy = wsme_json.fromjson(self._type, body)
self.assertEqual(constants.MAX_POLICY_POSITION, l7policy.position)
self.assertEqual(url, l7policy.redirect_url)
self.assertEqual(wsme_types.Unset, l7policy.redirect_pool_id)
def test_invalid_position(self):
body = {"listener_id": self.listener_id,
"action": constants.L7POLICY_ACTION_REJECT,
"position": "notvalid"}
self.assertRaises(ValueError, wsme_json.fromjson, self._type,
body)
def test_l7policy_min_position(self):
body = {"listener_id": self.listener_id,
"action": constants.L7POLICY_ACTION_REJECT,
"position": constants.MIN_POLICY_POSITION - 1}
self.assertRaises(
exc.InvalidInput, wsme_json.fromjson, self._type, body)
body = {"listener_id": self.listener_id,
"action": constants.L7POLICY_ACTION_REJECT,
"position": constants.MIN_POLICY_POSITION}
l7policy = wsme_json.fromjson(self._type, body)
self.assertEqual(constants.MIN_POLICY_POSITION, l7policy.position)
def test_l7policy_max_position(self):
body = {"listener_id": self.listener_id,
"action": constants.L7POLICY_ACTION_REJECT,
"position": constants.MAX_POLICY_POSITION + 1}
self.assertRaises(
exc.InvalidInput, wsme_json.fromjson, self._type, body)
body = {"listener_id": self.listener_id,
"action": constants.L7POLICY_ACTION_REJECT,
"position": constants.MAX_POLICY_POSITION}
l7policy = wsme_json.fromjson(self._type, body)
self.assertEqual(constants.MAX_POLICY_POSITION, l7policy.position)
def test_invalid_admin_state_up(self):
body = {"listener_id": self.listener_id,
"action": constants.L7POLICY_ACTION_REJECT,
"admin_state_up": "notvalid"}
self.assertRaises(ValueError, wsme_json.fromjson, self._type,
body)
def test_invalid_url(self):
body = {"listener_id": self.listener_id,
"action": constants.L7POLICY_ACTION_REDIRECT_TO_URL,
"redirect_url": "notvalid"}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson, self._type,
body)
class TestL7PolicyPUT(base.BaseTypesTest):
_type = l7policy_type.L7PolicyPUT
def test_l7policy(self):
body = {"action": constants.L7POLICY_ACTION_REJECT,
"position": constants.MIN_POLICY_POSITION}
l7policy = wsme_json.fromjson(self._type, body)
self.assertEqual(constants.MIN_POLICY_POSITION, l7policy.position)
self.assertEqual(wsme_types.Unset, l7policy.redirect_url)
self.assertEqual(wsme_types.Unset, l7policy.redirect_pool_id)
def test_l7policy_min_position(self):
body = {"position": constants.MIN_POLICY_POSITION - 1}
self.assertRaises(
exc.InvalidInput, wsme_json.fromjson, self._type, body)
body = {"position": constants.MIN_POLICY_POSITION}
l7policy = wsme_json.fromjson(self._type, body)
self.assertEqual(constants.MIN_POLICY_POSITION, l7policy.position)
def test_l7policy_max_position(self):
body = {"position": constants.MAX_POLICY_POSITION + 1}
self.assertRaises(
exc.InvalidInput, wsme_json.fromjson, self._type, body)
body = {"position": constants.MAX_POLICY_POSITION}
l7policy = wsme_json.fromjson(self._type, body)
self.assertEqual(constants.MAX_POLICY_POSITION, l7policy.position)
def test_invalid_position(self):
body = {"position": "test"}
self.assertRaises(ValueError, wsme_json.fromjson, self._type, body)
def test_invalid_action(self):
body = {"action": "test"}
self.assertRaises(exc.InvalidInput, wsme_json.fromjson, self._type,
body)

View File

@ -1871,7 +1871,8 @@ class TestDatabaseTasks(base.TestCase):
mock_l7policy_repo_update.assert_called_once_with(
'TEST',
L7POLICY_ID,
provisioning_status=constants.ACTIVE)
provisioning_status=constants.ACTIVE,
operating_status=constants.ONLINE)
# Test the revert
mock_l7policy_repo_update.reset_mock()