NSXv3: Refactor LBaaS L7 code
Refactor L7 code to support multiple l7 rules in a policy, and fix the position of lb rule in the virtual server. Change-Id: I08e10ecc6ef594c5539fe7315ffa3da51b2184d8
This commit is contained in:
parent
60c44020eb
commit
410575e5e7
@ -633,29 +633,22 @@ def delete_nsx_lbaas_monitor_binding(session, loadbalancer_id, pool_id,
|
||||
pool_id=pool_id, hm_id=hm_id).delete())
|
||||
|
||||
|
||||
def add_nsx_lbaas_l7rule_binding(session, loadbalancer_id, l7policy_id,
|
||||
l7rule_id, lb_rule_id, lb_vs_id):
|
||||
def add_nsx_lbaas_l7policy_binding(session, l7policy_id, lb_rule_id, lb_vs_id):
|
||||
with session.begin(subtransactions=True):
|
||||
binding = nsx_models.NsxLbaasL7Rule(
|
||||
loadbalancer_id=loadbalancer_id, l7policy_id=l7policy_id,
|
||||
l7rule_id=l7rule_id, lb_rule_id=lb_rule_id, lb_vs_id=lb_vs_id)
|
||||
binding = nsx_models.NsxLbaasL7Policy(
|
||||
l7policy_id=l7policy_id, lb_rule_id=lb_rule_id, lb_vs_id=lb_vs_id)
|
||||
session.add(binding)
|
||||
return binding
|
||||
|
||||
|
||||
def get_nsx_lbaas_l7rule_binding(session, loadbalancer_id, l7policy_id,
|
||||
l7rule_id):
|
||||
def get_nsx_lbaas_l7policy_binding(session, l7policy_id):
|
||||
try:
|
||||
return session.query(nsx_models.NsxLbaasL7Rule).filter_by(
|
||||
loadbalancer_id=loadbalancer_id, l7policy_id=l7policy_id,
|
||||
l7rule_id=l7rule_id).one()
|
||||
return session.query(nsx_models.NsxLbaasL7Policy).filter_by(
|
||||
l7policy_id=l7policy_id).one()
|
||||
except exc.NoResultFound:
|
||||
return
|
||||
|
||||
|
||||
def delete_nsx_lbaas_l7rule_binding(session, loadbalancer_id, l7policy_id,
|
||||
l7rule_id):
|
||||
return (session.query(nsx_models.NsxLbaasL7Rule).
|
||||
filter_by(loadbalancer_id=loadbalancer_id,
|
||||
l7policy_id=l7policy_id,
|
||||
l7rule_id=l7rule_id).delete())
|
||||
def delete_nsx_lbaas_l7policy_binding(session, l7policy_id):
|
||||
return (session.query(nsx_models.NsxLbaasL7Policy).
|
||||
filter_by(l7policy_id=l7policy_id).delete())
|
||||
|
@ -1 +1 @@
|
||||
a1be06050b41
|
||||
717f7f63a219
|
||||
|
@ -0,0 +1,62 @@
|
||||
# Copyright 2017 VMware, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""nsxv3_lbaas_l7policy
|
||||
|
||||
Revision ID: 717f7f63a219
|
||||
Revises: a1be06050b41
|
||||
Create Date: 2017-10-26 08:32:40.846088
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '717f7f63a219'
|
||||
down_revision = 'a1be06050b41'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
from neutron.db import migration
|
||||
|
||||
|
||||
def upgrade():
|
||||
|
||||
if migration.schema_has_table('nsxv3_lbaas_l7rules'):
|
||||
op.drop_constraint('fk_nsxv3_lbaas_l7rules_id', 'nsxv3_lbaas_l7rules',
|
||||
'foreignkey')
|
||||
op.drop_constraint('l7rule_id', 'nsxv3_lbaas_l7rules', 'primary')
|
||||
op.drop_column('nsxv3_lbaas_l7rules', 'loadbalancer_id')
|
||||
op.drop_column('nsxv3_lbaas_l7rules', 'l7rule_id')
|
||||
op.rename_table('nsxv3_lbaas_l7rules', 'nsxv3_lbaas_l7policies')
|
||||
|
||||
if migration.schema_has_table('lbaas_l7policies'):
|
||||
op.create_foreign_key(
|
||||
'fk_nsxv3_lbaas_l7policies_id', 'nsxv3_lbaas_l7policies',
|
||||
'lbaas_l7policies', ['l7policy_id'], ['id'],
|
||||
ondelete='CASCADE')
|
||||
else:
|
||||
op.create_table(
|
||||
'nsxv3_lbaas_l7policies',
|
||||
sa.Column('l7policy_id', sa.String(36), nullable=False),
|
||||
sa.Column('lb_rule_id', sa.String(36), nullable=False),
|
||||
sa.Column('lb_vs_id', sa.String(36), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('l7policy_id'))
|
||||
|
||||
if migration.schema_has_table('lbaas_l7policies'):
|
||||
op.create_foreign_key(
|
||||
'fk_nsxv3_lbaas_l7policies_id', 'nsxv3_lbaas_l7policies',
|
||||
'lbaas_l7policies', ['l7policy_id'], ['id'],
|
||||
ondelete='CASCADE')
|
@ -451,7 +451,14 @@ class NsxLbaasMonitor(model_base.BASEV2, models.TimestampMixin):
|
||||
|
||||
|
||||
class NsxLbaasL7Rule(model_base.BASEV2, models.TimestampMixin):
|
||||
"""Stores the mapping between LBaaS monitor and NSX LB monitor"""
|
||||
"""Stores the mapping between LBaaS monitor and NSX LB monitor
|
||||
|
||||
This table is only used in Pike and obsoleted since Queen as the
|
||||
mapping has been stored in nsxv3_lbaas_l7policies table instead.
|
||||
This original table was added in pike so that we cannot change
|
||||
DB migration script there, but instead we update the table with
|
||||
a new db migration script in Queen.
|
||||
"""
|
||||
__tablename__ = 'nsxv3_lbaas_l7rules'
|
||||
loadbalancer_id = sa.Column(sa.String(36), primary_key=True)
|
||||
l7policy_id = sa.Column(sa.String(36), primary_key=True)
|
||||
@ -462,3 +469,15 @@ class NsxLbaasL7Rule(model_base.BASEV2, models.TimestampMixin):
|
||||
primary_key=True)
|
||||
lb_rule_id = sa.Column(sa.String(36), nullable=False)
|
||||
lb_vs_id = sa.Column(sa.String(36), nullable=False)
|
||||
|
||||
|
||||
class NsxLbaasL7Policy(model_base.BASEV2, models.TimestampMixin):
|
||||
"""Stores the mapping between LBaaS l7policy and NSX LB rule"""
|
||||
__tablename__ = 'nsxv3_lbaas_l7policies'
|
||||
l7policy_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('lbaas_l7policies.id',
|
||||
name='fk_nsxv3_lbaas_l7policies_id',
|
||||
ondelete="CASCADE"),
|
||||
primary_key=True)
|
||||
lb_rule_id = sa.Column(sa.String(36), nullable=False)
|
||||
lb_vs_id = sa.Column(sa.String(36), nullable=False)
|
||||
|
@ -79,7 +79,7 @@ LB_LB_NAME = 'os-lbaas-lb-name'
|
||||
LB_LISTENER_TYPE = 'os-lbaas-listener-id'
|
||||
LB_HM_TYPE = 'os-lbaas-hm-id'
|
||||
LB_POOL_TYPE = 'os-lbaas-pool-id'
|
||||
LB_L7RULE_TYPE = 'os-lbaas-l7rule-id'
|
||||
LB_L7POLICY_TYPE = 'os-lbaas-l7policy-id'
|
||||
LB_HTTP_PROFILE = 'LbHttpProfile'
|
||||
LB_TCP_PROFILE = 'LbFastTcpProfile'
|
||||
LB_UDP_PROFILE = 'LbFastUdpProfile'
|
||||
|
@ -16,10 +16,13 @@
|
||||
from neutron_lib import exceptions as n_exc
|
||||
from oslo_log import helpers as log_helpers
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
|
||||
from vmware_nsx._i18n import _
|
||||
from vmware_nsx.db import db as nsx_db
|
||||
from vmware_nsx.services.lbaas import base_mgr
|
||||
from vmware_nsx.services.lbaas import lb_const
|
||||
from vmware_nsx.services.lbaas.nsx_v3 import lb_utils
|
||||
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -31,33 +34,92 @@ class EdgeL7PolicyManager(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
super(EdgeL7PolicyManager, self).__init__()
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def _l7policy_action(self, context, policy, action, delete=False):
|
||||
try:
|
||||
self.lbv2_driver.l7policy.successful_completion(
|
||||
context, policy, delete=delete)
|
||||
except Exception as e:
|
||||
self.lbv2_driver.l7policy.failed_completion(context, policy)
|
||||
msg = (_('Failed to %(action)s l7policy %(err)s') %
|
||||
{'action': action, 'err': e})
|
||||
resource = 'lbaas-l7policy-%s' % action
|
||||
raise n_exc.BadRequest(resource=resource, msg=msg)
|
||||
def _update_policy_position(self, vs_id, rule_id, position):
|
||||
vs_client = self.core_plugin.nsxlib.load_balancer.virtual_server
|
||||
vs = vs_client.get(vs_id)
|
||||
lb_rules = vs.get('rule_ids', [])
|
||||
if rule_id in lb_rules:
|
||||
lb_rules.remove(rule_id)
|
||||
if len(lb_rules) < position:
|
||||
lb_rules.append(rule_id)
|
||||
else:
|
||||
lb_rules.insert(position - 1, rule_id)
|
||||
vs_client.update(vs_id, rule_ids=lb_rules)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def create(self, context, policy):
|
||||
self._l7policy_action(context, policy, 'create')
|
||||
lb_id = policy.listener.loadbalancer_id
|
||||
listener_id = policy.listener_id
|
||||
rule_client = self.core_plugin.nsxlib.load_balancer.rule
|
||||
tags = lb_utils.get_tags(self.core_plugin, policy.id,
|
||||
lb_const.LB_L7POLICY_TYPE,
|
||||
policy.tenant_id, context.project_name)
|
||||
|
||||
binding = nsx_db.get_nsx_lbaas_listener_binding(
|
||||
context.session, lb_id, listener_id)
|
||||
if not binding:
|
||||
self.lbv2_driver.l7policy.failed_completion(context, policy)
|
||||
msg = _('Cannot find nsx lbaas binding for listener '
|
||||
'%(listener_id)s') % {'listener_id': listener_id}
|
||||
raise n_exc.BadRequest(resource='lbaas-l7policy-create', msg=msg)
|
||||
|
||||
vs_id = binding['lb_vs_id']
|
||||
rule_body = lb_utils.convert_l7policy_to_lb_rule(context, policy)
|
||||
try:
|
||||
lb_rule = rule_client.create(tags=tags, **rule_body)
|
||||
except nsxlib_exc.ManagerError:
|
||||
with excutils.save_and_reraise_exception():
|
||||
self.lbv2_driver.l7policy.failed_completion(context, policy)
|
||||
LOG.error('Failed to create lb rule at NSX backend')
|
||||
try:
|
||||
self._update_policy_position(vs_id, lb_rule['id'],
|
||||
policy.position)
|
||||
except nsxlib_exc.ManagerError:
|
||||
with excutils.save_and_reraise_exception():
|
||||
self.lbv2_driver.l7policy.failed_completion(context, policy)
|
||||
LOG.error('Failed to add rule %(rule)% to virtual server '
|
||||
'%(vs)s at NSX backend', {'rule': lb_rule['id'],
|
||||
'vs': vs_id})
|
||||
|
||||
nsx_db.add_nsx_lbaas_l7policy_binding(
|
||||
context.session, policy.id, lb_rule['id'], vs_id)
|
||||
self.lbv2_driver.l7policy.successful_completion(context, policy)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def update(self, context, old_policy, new_policy):
|
||||
self._l7policy_action(context, new_policy, 'update')
|
||||
rule_client = self.core_plugin.nsxlib.load_balancer.rule
|
||||
binding = nsx_db.get_nsx_lbaas_l7policy_binding(context.session,
|
||||
old_policy.id)
|
||||
if not binding:
|
||||
self.lbv2_driver.l7rule.failed_completion(context, new_policy)
|
||||
msg = _('Cannot find nsx lbaas binding for policy '
|
||||
'%(policy_id)s') % {'policy_id': old_policy.id}
|
||||
raise n_exc.BadRequest(resource='lbaas-l7policy-update', msg=msg)
|
||||
|
||||
vs_id = binding['lb_vs_id']
|
||||
lb_rule_id = binding['lb_rule_id']
|
||||
rule_body = lb_utils.convert_l7policy_to_lb_rule(context, new_policy)
|
||||
try:
|
||||
rule_client.update(lb_rule_id, **rule_body)
|
||||
if new_policy.position != old_policy.position:
|
||||
self._update_policy_position(vs_id, lb_rule_id,
|
||||
new_policy.position)
|
||||
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
self.lbv2_driver.l7policy.failed_completion(context,
|
||||
new_policy)
|
||||
LOG.error('Failed to update L7policy %(policy)s: '
|
||||
'%(err)s', {'policy': old_policy.id, 'err': e})
|
||||
|
||||
self.lbv2_driver.l7policy.successful_completion(context, new_policy)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def delete(self, context, policy):
|
||||
lb_id = policy.listener.loadbalancer_id
|
||||
vs_client = self.core_plugin.nsxlib.load_balancer.virtual_server
|
||||
rule_client = self.core_plugin.nsxlib.load_balancer.rule
|
||||
for rule in policy.rules:
|
||||
binding = nsx_db.get_nsx_lbaas_l7rule_binding(
|
||||
context.session, lb_id, policy.id, rule.id)
|
||||
binding = nsx_db.get_nsx_lbaas_l7policy_binding(context.session,
|
||||
policy.id)
|
||||
if binding:
|
||||
vs_id = binding['lb_vs_id']
|
||||
rule_id = binding['lb_rule_id']
|
||||
@ -72,10 +134,11 @@ class EdgeL7PolicyManager(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
self.lbv2_driver.l7policy.failed_completion(
|
||||
context, policy)
|
||||
msg = (_('Failed to delete lb rule: %(rule)s') %
|
||||
{'rule': rule.id})
|
||||
raise n_exc.BadRequest(resource='lbaas-l7rule-delete',
|
||||
{'rule': rule_id})
|
||||
raise n_exc.BadRequest(resource='lbaas-l7policy-delete',
|
||||
msg=msg)
|
||||
nsx_db.delete_nsx_lbaas_l7rule_binding(
|
||||
context.session, lb_id, policy.id, rule.id)
|
||||
nsx_db.delete_nsx_lbaas_l7policy_binding(
|
||||
context.session, policy.id)
|
||||
|
||||
self.lbv2_driver.l7policy.successful_completion(
|
||||
context, policy, delete=True)
|
||||
|
@ -16,14 +16,12 @@
|
||||
from neutron_lib import exceptions as n_exc
|
||||
from oslo_log import helpers as log_helpers
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
|
||||
from vmware_nsx._i18n import _
|
||||
from vmware_nsx.common import exceptions as nsx_exc
|
||||
from vmware_nsx.db import db as nsx_db
|
||||
from vmware_nsx.services.lbaas import base_mgr
|
||||
from vmware_nsx.services.lbaas import lb_const
|
||||
from vmware_nsx.services.lbaas.nsx_v3 import lb_utils
|
||||
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -33,171 +31,39 @@ class EdgeL7RuleManager(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
def __init__(self):
|
||||
super(EdgeL7RuleManager, self).__init__()
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def _get_rule_match_conditions(self, rule):
|
||||
match_conditions = []
|
||||
# values in rule have already been validated in LBaaS API,
|
||||
# we won't need to valid anymore in driver, and just get
|
||||
# the LB rule mapping from the dict.
|
||||
match_type = lb_const.LB_RULE_MATCH_TYPE[rule.compare_type]
|
||||
if rule.type == lb_const.L7_RULE_TYPE_COOKIE:
|
||||
header_value = rule.key + '=' + rule.value
|
||||
match_conditions.append(
|
||||
{'type': 'LbHttpRequestHeaderCondition',
|
||||
'match_type': match_type,
|
||||
'header_name': 'Cookie',
|
||||
'header_value': header_value})
|
||||
elif rule.type == lb_const.L7_RULE_TYPE_FILE_TYPE:
|
||||
match_conditions.append(
|
||||
{'type': 'LbHttpRequestUriCondition',
|
||||
'match_type': match_type,
|
||||
'uri': '*.' + rule.value})
|
||||
elif rule.type == lb_const.L7_RULE_TYPE_HEADER:
|
||||
match_conditions.append(
|
||||
{'type': 'LbHttpRequestHeaderCondition',
|
||||
'match_type': match_type,
|
||||
'header_name': rule.key,
|
||||
'header_value': rule.value})
|
||||
elif rule.type == lb_const.L7_RULE_TYPE_HOST_NAME:
|
||||
match_conditions.append(
|
||||
{'type': 'LbHttpRequestHeaderCondition',
|
||||
'match_type': match_type,
|
||||
'header_name': 'Host',
|
||||
'header_value': rule.value})
|
||||
elif rule.type == lb_const.L7_RULE_TYPE_PATH:
|
||||
match_conditions.append(
|
||||
{'type': 'LbHttpRequestUriCondition',
|
||||
'match_type': match_type,
|
||||
'uri': rule.value})
|
||||
else:
|
||||
msg = (_('l7rule type %(type)s is not supported in LBaaS') %
|
||||
{'type': rule.type})
|
||||
LOG.error(msg)
|
||||
raise n_exc.BadRequest(resource='lbaas-l7rule', msg=msg)
|
||||
return match_conditions
|
||||
def _update_l7rule_change(self, context, rule, delete=False):
|
||||
rule_client = self.core_plugin.nsxlib.load_balancer.rule
|
||||
binding = nsx_db.get_nsx_lbaas_l7policy_binding(context.session,
|
||||
rule.policy.id)
|
||||
if not binding:
|
||||
self.lbv2_driver.l7rule.failed_completion(context, rule)
|
||||
msg = _('Cannot find nsx lbaas binding for policy '
|
||||
'%(policy_id)s') % {'policy_id': rule.policy.id}
|
||||
raise n_exc.BadRequest(resource='lbaas-l7policy-update', msg=msg)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def _get_rule_actions(self, context, rule):
|
||||
lb_id = rule.policy.listener.loadbalancer_id
|
||||
l7policy = rule.policy
|
||||
if l7policy.action == lb_const.L7_POLICY_ACTION_REDIRECT_TO_POOL:
|
||||
pool_binding = nsx_db.get_nsx_lbaas_pool_binding(
|
||||
context.session, lb_id, l7policy.redirect_pool_id)
|
||||
if pool_binding:
|
||||
lb_pool_id = pool_binding['lb_pool_id']
|
||||
actions = [{'type': lb_const.LB_SELECT_POOL_ACTION,
|
||||
'pool_id': lb_pool_id}]
|
||||
else:
|
||||
msg = _('Failed to get LB pool binding from nsx db')
|
||||
raise n_exc.BadRequest(resource='lbaas-l7rule-create',
|
||||
msg=msg)
|
||||
elif l7policy.action == lb_const.L7_POLICY_ACTION_REDIRECT_TO_URL:
|
||||
actions = [{'type': lb_const.LB_HTTP_REDIRECT_ACTION,
|
||||
'redirect_status': lb_const.LB_HTTP_REDIRECT_STATUS,
|
||||
'redirect_url': l7policy.redirect_url}]
|
||||
elif l7policy.action == lb_const.L7_POLICY_ACTION_REJECT:
|
||||
actions = [{'type': lb_const.LB_REJECT_ACTION,
|
||||
'reply_status': lb_const.LB_HTTP_REJECT_STATUS}]
|
||||
else:
|
||||
msg = (_('Invalid l7policy action: %(action)s') %
|
||||
{'action': l7policy.action})
|
||||
raise n_exc.BadRequest(resource='lbaas-l7rule-create',
|
||||
msg=msg)
|
||||
return actions
|
||||
lb_rule_id = binding['lb_rule_id']
|
||||
if delete:
|
||||
lb_utils.remove_rule_from_policy(rule)
|
||||
rule_body = lb_utils.convert_l7policy_to_lb_rule(context, rule.policy)
|
||||
try:
|
||||
rule_client.update(lb_rule_id, **rule_body)
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
self.lbv2_driver.l7rule.failed_completion(context, rule)
|
||||
LOG.error('Failed to update L7policy %(policy)s: '
|
||||
'%(err)s', {'policy': rule.policy.id, 'err': e})
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def _convert_l7policy_to_lb_rule(self, context, rule):
|
||||
body = {}
|
||||
body['match_conditions'] = self._get_rule_match_conditions(rule)
|
||||
body['actions'] = self._get_rule_actions(context, rule)
|
||||
body['phase'] = lb_const.LB_RULE_HTTP_FORWARDING
|
||||
body['match_strategy'] = 'ANY'
|
||||
|
||||
return body
|
||||
self.lbv2_driver.l7rule.successful_completion(context, rule,
|
||||
delete=delete)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def create(self, context, rule):
|
||||
lb_id = rule.policy.listener.loadbalancer_id
|
||||
listener_id = rule.policy.listener_id
|
||||
vs_client = self.core_plugin.nsxlib.load_balancer.virtual_server
|
||||
rule_client = self.core_plugin.nsxlib.load_balancer.rule
|
||||
tags = lb_utils.get_tags(self.core_plugin, rule.id,
|
||||
lb_const.LB_L7RULE_TYPE,
|
||||
rule.tenant_id, context.project_name)
|
||||
|
||||
binding = nsx_db.get_nsx_lbaas_listener_binding(
|
||||
context.session, lb_id, listener_id)
|
||||
if not binding:
|
||||
msg = _('Cannot find nsx lbaas binding for listener '
|
||||
'%(listener_id)s') % {'listener_id': listener_id}
|
||||
raise n_exc.BadRequest(resource='lbaas-l7rule-create', msg=msg)
|
||||
|
||||
vs_id = binding['lb_vs_id']
|
||||
rule_body = self._convert_l7policy_to_lb_rule(context, rule)
|
||||
try:
|
||||
lb_rule = rule_client.create(tags=tags, **rule_body)
|
||||
except nsxlib_exc.ManagerError:
|
||||
self.lbv2_driver.l7rule.failed_completion(context, rule)
|
||||
msg = _('Failed to create lb rule at NSX backend')
|
||||
raise n_exc.BadRequest(resource='lbaas-l7rule-create',
|
||||
msg=msg)
|
||||
try:
|
||||
vs_client.add_rule(vs_id, lb_rule['id'])
|
||||
except nsxlib_exc.ManagerError:
|
||||
self.lbv2_driver.l7rule.failed_completion(context, rule)
|
||||
msg = (_('Failed to add rule %(rule)s to virtual server '
|
||||
'%(vs)s at NSX backend') %
|
||||
{'rule': lb_rule['id'], 'vs': vs_id})
|
||||
raise n_exc.BadRequest(resource='lbaas-l7rule-create',
|
||||
msg=msg)
|
||||
|
||||
nsx_db.add_nsx_lbaas_l7rule_binding(
|
||||
context.session, lb_id, rule.l7policy_id, rule.id,
|
||||
lb_rule['id'], vs_id)
|
||||
self.lbv2_driver.l7rule.successful_completion(context, rule)
|
||||
self._update_l7rule_change(context, rule)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def update(self, context, old_rule, new_rule):
|
||||
self.lbv2_driver.l7rule.successful_completion(context, new_rule)
|
||||
self._update_l7rule_change(context, new_rule)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def delete(self, context, rule):
|
||||
lb_id = rule.policy.listener.loadbalancer_id
|
||||
vs_client = self.core_plugin.nsxlib.load_balancer.virtual_server
|
||||
rule_client = self.core_plugin.nsxlib.load_balancer.rule
|
||||
|
||||
binding = nsx_db.get_nsx_lbaas_l7rule_binding(
|
||||
context.session, lb_id, rule.l7policy_id, rule.id)
|
||||
if binding:
|
||||
vs_id = binding['lb_vs_id']
|
||||
rule_id = binding['lb_rule_id']
|
||||
try:
|
||||
vs_client.remove_rule(vs_id, rule_id)
|
||||
except nsx_exc.NsxResourceNotFound:
|
||||
msg = (_("virtual server cannot be found on nsx: %(vs)s") %
|
||||
{'vs': vs_id})
|
||||
raise n_exc.BadRequest(resource='lbaas-l7rule-delete',
|
||||
msg=msg)
|
||||
except nsxlib_exc.ManagerError:
|
||||
self.lbv2_driver.l7rule.failed_completion(context,
|
||||
rule)
|
||||
msg = (_('Failed to update rule %(rule)s on virtual server '
|
||||
'%(vs)s') % {'rule': rule_id, 'vs': vs_id})
|
||||
raise n_exc.BadRequest(resource='lbaas-l7rule-delete',
|
||||
msg=msg)
|
||||
try:
|
||||
rule_client.delete(rule_id)
|
||||
except nsx_exc.NsxResourceNotFound:
|
||||
LOG.warning("LB rule cannot be found on nsx: %(rule)s",
|
||||
{'rule': rule_id})
|
||||
except nsxlib_exc.ManagerError:
|
||||
self.lbv2_driver.l7rule.failed_completion(context,
|
||||
rule)
|
||||
msg = (_('Failed to delete lb rule: %(rule)s') %
|
||||
{'rule': rule.id})
|
||||
raise n_exc.BadRequest(resource='lbaas-l7rule-delete',
|
||||
msg=msg)
|
||||
nsx_db.delete_nsx_lbaas_l7rule_binding(
|
||||
context.session, lb_id, rule.l7policy_id, rule.id)
|
||||
self.lbv2_driver.l7rule.successful_completion(context, rule,
|
||||
delete=True)
|
||||
self._update_l7rule_change(context, rule, delete=True)
|
||||
|
@ -18,6 +18,7 @@ from neutron.services.flavors import flavors_plugin
|
||||
from neutron_lib import exceptions as n_exc
|
||||
|
||||
from vmware_nsx._i18n import _
|
||||
from vmware_nsx.db import db as nsx_db
|
||||
from vmware_nsx.services.lbaas import lb_const
|
||||
from vmware_nsxlib.v3 import utils
|
||||
|
||||
@ -92,3 +93,88 @@ def validate_lb_subnet(context, plugin, subnet_id):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def get_rule_match_conditions(policy):
|
||||
match_conditions = []
|
||||
# values in rule have already been validated in LBaaS API,
|
||||
# we won't need to valid anymore in driver, and just get
|
||||
# the LB rule mapping from the dict.
|
||||
for rule in policy.rules:
|
||||
match_type = lb_const.LB_RULE_MATCH_TYPE[rule.compare_type]
|
||||
if rule.type == lb_const.L7_RULE_TYPE_COOKIE:
|
||||
header_value = rule.key + '=' + rule.value
|
||||
match_conditions.append(
|
||||
{'type': 'LbHttpRequestHeaderCondition',
|
||||
'match_type': match_type,
|
||||
'header_name': 'Cookie',
|
||||
'header_value': header_value})
|
||||
elif rule.type == lb_const.L7_RULE_TYPE_FILE_TYPE:
|
||||
match_conditions.append(
|
||||
{'type': 'LbHttpRequestUriCondition',
|
||||
'match_type': match_type,
|
||||
'uri': '*.' + rule.value})
|
||||
elif rule.type == lb_const.L7_RULE_TYPE_HEADER:
|
||||
match_conditions.append(
|
||||
{'type': 'LbHttpRequestHeaderCondition',
|
||||
'match_type': match_type,
|
||||
'header_name': rule.key,
|
||||
'header_value': rule.value})
|
||||
elif rule.type == lb_const.L7_RULE_TYPE_HOST_NAME:
|
||||
match_conditions.append(
|
||||
{'type': 'LbHttpRequestHeaderCondition',
|
||||
'match_type': match_type,
|
||||
'header_name': 'Host',
|
||||
'header_value': rule.value})
|
||||
elif rule.type == lb_const.L7_RULE_TYPE_PATH:
|
||||
match_conditions.append(
|
||||
{'type': 'LbHttpRequestUriCondition',
|
||||
'match_type': match_type,
|
||||
'uri': rule.value})
|
||||
else:
|
||||
msg = (_('l7rule type %(type)s is not supported in LBaaS') %
|
||||
{'type': rule.type})
|
||||
raise n_exc.BadRequest(resource='lbaas-l7rule', msg=msg)
|
||||
return match_conditions
|
||||
|
||||
|
||||
def get_rule_actions(context, l7policy):
|
||||
lb_id = l7policy.listener.loadbalancer_id
|
||||
if l7policy.action == lb_const.L7_POLICY_ACTION_REDIRECT_TO_POOL:
|
||||
pool_binding = nsx_db.get_nsx_lbaas_pool_binding(
|
||||
context.session, lb_id, l7policy.redirect_pool_id)
|
||||
if pool_binding:
|
||||
lb_pool_id = pool_binding['lb_pool_id']
|
||||
actions = [{'type': lb_const.LB_SELECT_POOL_ACTION,
|
||||
'pool_id': lb_pool_id}]
|
||||
else:
|
||||
msg = _('Failed to get LB pool binding from nsx db')
|
||||
raise n_exc.BadRequest(resource='lbaas-l7rule-create',
|
||||
msg=msg)
|
||||
elif l7policy.action == lb_const.L7_POLICY_ACTION_REDIRECT_TO_URL:
|
||||
actions = [{'type': lb_const.LB_HTTP_REDIRECT_ACTION,
|
||||
'redirect_status': lb_const.LB_HTTP_REDIRECT_STATUS,
|
||||
'redirect_url': l7policy.redirect_url}]
|
||||
elif l7policy.action == lb_const.L7_POLICY_ACTION_REJECT:
|
||||
actions = [{'type': lb_const.LB_REJECT_ACTION,
|
||||
'reply_status': lb_const.LB_HTTP_REJECT_STATUS}]
|
||||
else:
|
||||
msg = (_('Invalid l7policy action: %(action)s') %
|
||||
{'action': l7policy.action})
|
||||
raise n_exc.BadRequest(resource='lbaas-l7rule-create',
|
||||
msg=msg)
|
||||
return actions
|
||||
|
||||
|
||||
def convert_l7policy_to_lb_rule(context, policy):
|
||||
return {
|
||||
'match_conditions': get_rule_match_conditions(policy),
|
||||
'actions': get_rule_actions(context, policy),
|
||||
'phase': lb_const.LB_RULE_HTTP_FORWARDING,
|
||||
'match_strategy': 'ALL'
|
||||
}
|
||||
|
||||
|
||||
def remove_rule_from_policy(rule):
|
||||
l7rules = rule.policy.rules
|
||||
rule.policy.rules = [r for r in l7rules if r.id != rule.id]
|
||||
|
@ -98,9 +98,7 @@ HM_BINDING = {'loadbalancer_id': LB_ID,
|
||||
L7POLICY_ID = 'l7policy-xxx'
|
||||
LB_RULE_ID = 'lb-rule-xx'
|
||||
L7RULE_ID = 'l7rule-111'
|
||||
L7RULE_BINDING = {'loadbalancer_id': LB_ID,
|
||||
'policy_id': L7POLICY_ID,
|
||||
'rule_id': L7RULE_ID,
|
||||
L7POLICY_BINDING = {'l7policy_id': L7POLICY_ID,
|
||||
'lb_vs_id': LB_VS_ID,
|
||||
'lb_rule_id': LB_RULE_ID}
|
||||
|
||||
@ -152,7 +150,7 @@ class BaseTestEdgeLbaasV2(base.BaseTestCase):
|
||||
description='policy-desc',
|
||||
listener_id=LISTENER_ID,
|
||||
action='REDIRECT_TO_POOL',
|
||||
redirect_pool_id=LB_POOL_ID,
|
||||
redirect_pool_id=POOL_ID,
|
||||
listener=self.listener,
|
||||
position=1)
|
||||
self.l7rule = lb_models.L7Rule(L7RULE_ID, LB_TENANT_ID,
|
||||
@ -660,11 +658,33 @@ class TestEdgeLbaasV2L7Policy(BaseTestEdgeLbaasV2):
|
||||
return 'l7policy'
|
||||
|
||||
def test_create(self):
|
||||
with mock.patch.object(nsx_db, 'get_nsx_lbaas_listener_binding'
|
||||
) as mock_get_listener_binding, \
|
||||
mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
|
||||
) as mock_get_pool_binding, \
|
||||
mock.patch.object(self.rule_client, 'create'
|
||||
) as mock_create_rule, \
|
||||
mock.patch.object(self.vs_client, 'get'
|
||||
) as mock_get_virtual_server, \
|
||||
mock.patch.object(self.vs_client, 'update'
|
||||
) as mock_update_virtual_server, \
|
||||
mock.patch.object(nsx_db, 'add_nsx_lbaas_l7policy_binding'
|
||||
) as mock_add_l7policy_binding:
|
||||
mock_get_listener_binding.return_value = LISTENER_BINDING
|
||||
mock_get_pool_binding.return_value = POOL_BINDING
|
||||
mock_create_rule.return_value = {'id': LB_RULE_ID}
|
||||
mock_get_virtual_server.return_value = {'id': LB_VS_ID}
|
||||
|
||||
self.edge_driver.l7policy.create(self.context, self.l7policy)
|
||||
|
||||
mock_update_virtual_server.assert_called_with(
|
||||
LB_VS_ID, rule_ids=[LB_RULE_ID])
|
||||
mock_add_l7policy_binding.assert_called_with(
|
||||
self.context.session, L7POLICY_ID, LB_RULE_ID, LB_VS_ID)
|
||||
mock_successful_completion = (
|
||||
self.lbv2_driver.l7policy.successful_completion)
|
||||
mock_successful_completion.assert_called_with(
|
||||
self.context, self.l7policy, delete=False)
|
||||
mock_successful_completion.assert_called_with(self.context,
|
||||
self.l7policy)
|
||||
|
||||
def test_update(self):
|
||||
new_l7policy = lb_models.L7Policy(L7POLICY_ID, LB_TENANT_ID,
|
||||
@ -672,16 +692,62 @@ class TestEdgeLbaasV2L7Policy(BaseTestEdgeLbaasV2):
|
||||
listener_id=LISTENER_ID,
|
||||
action='REJECT',
|
||||
listener=self.listener,
|
||||
position=1)
|
||||
position=2)
|
||||
vs_with_rules = {
|
||||
'id': LB_VS_ID,
|
||||
'rule_ids': [LB_RULE_ID, 'abc', 'xyz']
|
||||
}
|
||||
rule_body = {
|
||||
'match_conditions': [],
|
||||
'actions': [{
|
||||
'type': 'LbHttpRejectAction',
|
||||
'reply_status': '403'}],
|
||||
'phase': 'HTTP_FORWARDING',
|
||||
'match_strategy': 'ALL'
|
||||
}
|
||||
with mock.patch.object(nsx_db, 'get_nsx_lbaas_l7policy_binding'
|
||||
) as mock_get_l7policy_binding, \
|
||||
mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
|
||||
) as mock_get_pool_binding, \
|
||||
mock.patch.object(self.rule_client, 'update'
|
||||
) as mock_update_rule, \
|
||||
mock.patch.object(self.vs_client, 'get'
|
||||
) as mock_get_virtual_server, \
|
||||
mock.patch.object(self.vs_client, 'update'
|
||||
) as mock_update_virtual_server:
|
||||
mock_get_l7policy_binding.return_value = L7POLICY_BINDING
|
||||
mock_get_pool_binding.return_value = POOL_BINDING
|
||||
mock_get_virtual_server.return_value = vs_with_rules
|
||||
|
||||
self.edge_driver.l7policy.update(self.context, self.l7policy,
|
||||
new_l7policy)
|
||||
|
||||
mock_update_rule.assert_called_with(LB_RULE_ID,
|
||||
**rule_body)
|
||||
mock_update_virtual_server.assert_called_with(
|
||||
LB_VS_ID, rule_ids=['abc', LB_RULE_ID, 'xyz'])
|
||||
mock_successful_completion = (
|
||||
self.lbv2_driver.l7policy.successful_completion)
|
||||
mock_successful_completion.assert_called_with(
|
||||
self.context, new_l7policy, delete=False)
|
||||
mock_successful_completion.assert_called_with(self.context,
|
||||
new_l7policy)
|
||||
|
||||
def test_delete(self):
|
||||
with mock.patch.object(nsx_db, 'get_nsx_lbaas_l7policy_binding'
|
||||
) as mock_get_l7policy_binding, \
|
||||
mock.patch.object(self.vs_client, 'remove_rule'
|
||||
) as mock_vs_remove_rule, \
|
||||
mock.patch.object(self.rule_client, 'delete'
|
||||
) as mock_delete_rule, \
|
||||
mock.patch.object(nsx_db, 'delete_nsx_lbaas_l7policy_binding'
|
||||
) as mock_delete_l7policy_binding:
|
||||
mock_get_l7policy_binding.return_value = L7POLICY_BINDING
|
||||
|
||||
self.edge_driver.l7policy.delete(self.context, self.l7policy)
|
||||
|
||||
mock_vs_remove_rule.assert_called_with(LB_VS_ID, LB_RULE_ID)
|
||||
mock_delete_rule.assert_called_with(LB_RULE_ID)
|
||||
mock_delete_l7policy_binding.assert_called_with(
|
||||
self.context.session, L7POLICY_ID)
|
||||
mock_successful_completion = (
|
||||
self.lbv2_driver.l7policy.successful_completion)
|
||||
mock_successful_completion.assert_called_with(
|
||||
@ -697,31 +763,39 @@ class TestEdgeLbaasV2L7Rule(BaseTestEdgeLbaasV2):
|
||||
return 'l7rule'
|
||||
|
||||
def test_create(self):
|
||||
with mock.patch.object(nsx_db, 'get_nsx_lbaas_listener_binding',
|
||||
) as mock_get_listnener_binding, \
|
||||
mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding',
|
||||
self.l7policy.rules = [self.l7rule]
|
||||
create_rule_body = {
|
||||
'match_conditions': [{
|
||||
'type': 'LbHttpRequestHeaderCondition',
|
||||
'match_type': 'EQUALS',
|
||||
'header_name': self.l7rule.key,
|
||||
'header_value': self.l7rule.value}],
|
||||
'actions': [{
|
||||
'type': 'LbSelectPoolAction',
|
||||
'pool_id': LB_POOL_ID}],
|
||||
'phase': 'HTTP_FORWARDING',
|
||||
'match_strategy': 'ALL'
|
||||
}
|
||||
|
||||
with mock.patch.object(nsx_db, 'get_nsx_lbaas_l7policy_binding'
|
||||
) as mock_get_l7policy_binding, \
|
||||
mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
|
||||
) as mock_get_pool_binding, \
|
||||
mock.patch.object(self.rule_client, 'create',
|
||||
) as mock_create_rule, \
|
||||
mock.patch.object(self.vs_client, 'add_rule',
|
||||
) as mock_add_rule, \
|
||||
mock.patch.object(nsx_db, 'add_nsx_lbaas_l7rule_binding',
|
||||
) as mock_add_l7rule_binding:
|
||||
mock_get_listnener_binding.return_value = LISTENER_BINDING
|
||||
mock.patch.object(self.rule_client, 'update'
|
||||
) as mock_update_rule:
|
||||
mock_get_l7policy_binding.return_value = L7POLICY_BINDING
|
||||
mock_get_pool_binding.return_value = POOL_BINDING
|
||||
mock_create_rule.return_value = {'id': LB_RULE_ID}
|
||||
|
||||
self.edge_driver.l7rule.create(self.context, self.l7rule)
|
||||
|
||||
mock_add_rule.assert_called_with(LB_VS_ID, LB_RULE_ID)
|
||||
mock_add_l7rule_binding.assert_called_with(
|
||||
self.context.session, LB_ID, L7POLICY_ID, L7RULE_ID,
|
||||
LB_RULE_ID, LB_VS_ID)
|
||||
mock_update_rule.assert_called_with(LB_RULE_ID,
|
||||
**create_rule_body)
|
||||
|
||||
mock_successful_completion = (
|
||||
self.lbv2_driver.l7rule.successful_completion)
|
||||
mock_successful_completion.assert_called_with(self.context,
|
||||
self.l7rule)
|
||||
self.l7rule,
|
||||
delete=False)
|
||||
|
||||
def test_update(self):
|
||||
new_l7rule = lb_models.L7Rule(L7RULE_ID, LB_TENANT_ID,
|
||||
@ -732,29 +806,65 @@ class TestEdgeLbaasV2L7Rule(BaseTestEdgeLbaasV2):
|
||||
key='cookie1',
|
||||
value='xxxxx',
|
||||
policy=self.l7policy)
|
||||
self.edge_driver.l7rule.update(self.context, self.l7rule, new_l7rule)
|
||||
self.l7policy.rules = [new_l7rule]
|
||||
update_rule_body = {
|
||||
'match_conditions': [{
|
||||
'type': 'LbHttpRequestHeaderCondition',
|
||||
'match_type': 'STARTS_WITH',
|
||||
'header_name': 'Cookie',
|
||||
'header_value': 'cookie1=xxxxx'}],
|
||||
'actions': [{
|
||||
'type': 'LbSelectPoolAction',
|
||||
'pool_id': LB_POOL_ID}],
|
||||
'phase': 'HTTP_FORWARDING',
|
||||
'match_strategy': 'ALL'
|
||||
}
|
||||
|
||||
with mock.patch.object(nsx_db, 'get_nsx_lbaas_l7policy_binding'
|
||||
) as mock_get_l7policy_binding, \
|
||||
mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
|
||||
) as mock_get_pool_binding, \
|
||||
mock.patch.object(self.rule_client, 'update'
|
||||
) as mock_update_rule:
|
||||
mock_get_l7policy_binding.return_value = L7POLICY_BINDING
|
||||
mock_get_pool_binding.return_value = POOL_BINDING
|
||||
|
||||
self.edge_driver.l7rule.update(self.context, self.l7rule,
|
||||
new_l7rule)
|
||||
|
||||
mock_update_rule.assert_called_with(LB_RULE_ID,
|
||||
**update_rule_body)
|
||||
|
||||
mock_successful_completion = (
|
||||
self.lbv2_driver.l7rule.successful_completion)
|
||||
mock_successful_completion.assert_called_with(
|
||||
self.context, new_l7rule)
|
||||
mock_successful_completion.assert_called_with(self.context,
|
||||
new_l7rule,
|
||||
delete=False)
|
||||
|
||||
def test_delete_pool_without_members(self):
|
||||
with mock.patch.object(nsx_db, 'get_nsx_lbaas_l7rule_binding',
|
||||
) as mock_get_l7rule_binding, \
|
||||
mock.patch.object(self.vs_client, 'remove_rule'
|
||||
) as mock_remove_rule, \
|
||||
mock.patch.object(self.rule_client, 'delete',
|
||||
) as mock_delete_rule, \
|
||||
mock.patch.object(nsx_db, 'delete_nsx_lbaas_l7rule_binding',
|
||||
) as mock_delete_l7rule_binding:
|
||||
mock_get_l7rule_binding.return_value = L7RULE_BINDING
|
||||
def test_delete(self):
|
||||
self.l7policy.rules = [self.l7rule]
|
||||
delete_rule_body = {
|
||||
'match_conditions': [],
|
||||
'actions': [{
|
||||
'type': 'LbSelectPoolAction',
|
||||
'pool_id': LB_POOL_ID}],
|
||||
'phase': 'HTTP_FORWARDING',
|
||||
'match_strategy': 'ALL'
|
||||
}
|
||||
|
||||
with mock.patch.object(nsx_db, 'get_nsx_lbaas_l7policy_binding'
|
||||
) as mock_get_l7policy_binding, \
|
||||
mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
|
||||
) as mock_get_pool_binding, \
|
||||
mock.patch.object(self.rule_client, 'update'
|
||||
) as mock_update_rule:
|
||||
mock_get_l7policy_binding.return_value = L7POLICY_BINDING
|
||||
mock_get_pool_binding.return_value = POOL_BINDING
|
||||
|
||||
self.edge_driver.l7rule.delete(self.context, self.l7rule)
|
||||
|
||||
mock_remove_rule.assert_called_with(LB_VS_ID, LB_RULE_ID)
|
||||
mock_delete_rule.assert_called_with(LB_RULE_ID)
|
||||
mock_delete_l7rule_binding.assert_called_with(
|
||||
self.context.session, LB_ID, L7POLICY_ID, L7RULE_ID)
|
||||
mock_update_rule.assert_called_with(LB_RULE_ID,
|
||||
**delete_rule_body)
|
||||
|
||||
mock_successful_completion = (
|
||||
self.lbv2_driver.l7rule.successful_completion)
|
||||
|
Loading…
Reference in New Issue
Block a user