From aa9da74ca726274ee603e0ea6f8e75ac5711284d Mon Sep 17 00:00:00 2001 From: Tong Liu Date: Fri, 21 Jul 2017 16:07:25 -0700 Subject: [PATCH] NSXv3: Add Neutron LBaaS Layer7 Support This patch adds support for LBaaS layer7 and implement the following LBaaS resources: - L7 Policy - L7 Rule Change-Id: If5a0fbeecae7c7d6e98667a1feb3a15aff3f7d70 --- vmware_nsx/db/db.py | 28 +++ .../ea7a72ab9643_nsxv3_lbaas_mapping.py | 17 ++ vmware_nsx/db/nsx_models.py | 14 ++ vmware_nsx/services/lbaas/lb_const.py | 6 +- .../services/lbaas/nsx_v3/l7policy_mgr.py | 53 +++++ .../services/lbaas/nsx_v3/l7rule_mgr.py | 189 ++++++++++++++++++ .../services/lbaas/nsx_v3/lb_driver_v2.py | 4 + vmware_nsx/services/lbaas/nsx_v3/pool_mgr.py | 4 +- .../unit/services/lbaas/test_nsxv3_driver.py | 145 +++++++++++++- 9 files changed, 457 insertions(+), 3 deletions(-) create mode 100644 vmware_nsx/services/lbaas/nsx_v3/l7policy_mgr.py create mode 100644 vmware_nsx/services/lbaas/nsx_v3/l7rule_mgr.py diff --git a/vmware_nsx/db/db.py b/vmware_nsx/db/db.py index c56d37fbb6..c89502dce6 100644 --- a/vmware_nsx/db/db.py +++ b/vmware_nsx/db/db.py @@ -593,3 +593,31 @@ def delete_nsx_lbaas_monitor_binding(session, loadbalancer_id, pool_id, return (session.query(nsx_models.NsxLbaasMonitor). filter_by(loadbalancer_id=loadbalancer_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): + 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) + session.add(binding) + return binding + + +def get_nsx_lbaas_l7rule_binding(session, loadbalancer_id, l7policy_id, + l7rule_id): + try: + return session.query(nsx_models.NsxLbaasL7Rule).filter_by( + loadbalancer_id=loadbalancer_id, l7policy_id=l7policy_id, + l7rule_id=l7rule_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()) diff --git a/vmware_nsx/db/migration/alembic_migrations/versions/pike/expand/ea7a72ab9643_nsxv3_lbaas_mapping.py b/vmware_nsx/db/migration/alembic_migrations/versions/pike/expand/ea7a72ab9643_nsxv3_lbaas_mapping.py index f198501f84..7bdb7d5213 100644 --- a/vmware_nsx/db/migration/alembic_migrations/versions/pike/expand/ea7a72ab9643_nsxv3_lbaas_mapping.py +++ b/vmware_nsx/db/migration/alembic_migrations/versions/pike/expand/ea7a72ab9643_nsxv3_lbaas_mapping.py @@ -72,6 +72,18 @@ def upgrade(): sa.Column('updated_at', sa.DateTime(), nullable=True), sa.PrimaryKeyConstraint('loadbalancer_id', 'pool_id', 'hm_id')) + op.create_table( + 'nsxv3_lbaas_l7rules', + sa.Column('loadbalancer_id', sa.String(36), nullable=False), + sa.Column('l7policy_id', sa.String(36), nullable=False), + sa.Column('l7rule_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('loadbalancer_id', 'l7policy_id', + 'l7rule_id')) + if migration.schema_has_table('lbaas_loadbalancers'): op.create_foreign_key( 'fk_nsxv3_lbaas_loadbalancers_id', 'nsxv3_lbaas_loadbalancers', @@ -92,3 +104,8 @@ def upgrade(): op.create_foreign_key( 'fk_nsxv3_lbaas_healthmonitors_id', 'nsxv3_lbaas_monitors', 'lbaas_healthmonitors', ['hm_id'], ['id'], ondelete='CASCADE') + + if migration.schema_has_table('lbaas_l7rules'): + op.create_foreign_key( + 'fk_nsxv3_lbaas_l7rules_id', 'nsxv3_lbaas_l7rules', + 'lbaas_l7rules', ['l7rule_id'], ['id'], ondelete='CASCADE') diff --git a/vmware_nsx/db/nsx_models.py b/vmware_nsx/db/nsx_models.py index a75d0b8ac5..c9c4a3087c 100644 --- a/vmware_nsx/db/nsx_models.py +++ b/vmware_nsx/db/nsx_models.py @@ -448,3 +448,17 @@ class NsxLbaasMonitor(model_base.BASEV2, models.TimestampMixin): primary_key=True) lb_monitor_id = sa.Column(sa.String(36), nullable=False) lb_pool_id = sa.Column(sa.String(36), nullable=False) + + +class NsxLbaasL7Rule(model_base.BASEV2, models.TimestampMixin): + """Stores the mapping between LBaaS monitor and NSX LB monitor""" + __tablename__ = 'nsxv3_lbaas_l7rules' + loadbalancer_id = sa.Column(sa.String(36), primary_key=True) + l7policy_id = sa.Column(sa.String(36), primary_key=True) + l7rule_id = sa.Column(sa.String(36), + sa.ForeignKey('lbaas_l7rules.id', + name='fk_nsxv3_lbaas_l7rules_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) diff --git a/vmware_nsx/services/lbaas/lb_const.py b/vmware_nsx/services/lbaas/lb_const.py index 80899f5b27..d4ac60a9b5 100644 --- a/vmware_nsx/services/lbaas/lb_const.py +++ b/vmware_nsx/services/lbaas/lb_const.py @@ -77,7 +77,8 @@ L7_RULE_COMPARE_TYPE_EQUAL_TO = 'EQUAL_TO' LB_LB_TYPE = 'os-lbaas-lb-id' LB_LISTENER_TYPE = 'os-lbaas-listener-id' LB_HM_TYPE = 'os-lbaas-hm-id' -LB_POOL_TYPE = 'os-lbaas-pool-type' +LB_POOL_TYPE = 'os-lbaas-pool-id' +LB_L7RULE_TYPE = 'os-lbaas-l7rule-id' LB_HTTP_PROFILE = 'LbHttpProfile' LB_TCP_PROFILE = 'LbFastTcpProfile' NSXV3_MONITOR_MAP = {LB_HEALTH_MONITOR_PING: 'LbIcmpMonitor', @@ -88,6 +89,9 @@ LB_STATS_MAP = {'active_connections': 'current_sessions', 'bytes_in': 'bytes_in', 'bytes_out': 'bytes_out', 'total_connections': 'total_sessions'} +LB_SELECT_POOL_ACTION = 'LbSelectPoolAction' +LB_HTTP_REDIRECT_ACTION = 'LbHttpRedirectAction' +LB_REJECT_ACTION = 'LbHttpRejectAction' LR_ROUTER_TYPE = 'os-neutron-router-id' LR_PORT_TYPE = 'os-neutron-rport-id' DEFAULT_LB_SIZE = 'SMALL' diff --git a/vmware_nsx/services/lbaas/nsx_v3/l7policy_mgr.py b/vmware_nsx/services/lbaas/nsx_v3/l7policy_mgr.py new file mode 100644 index 0000000000..92ec121dce --- /dev/null +++ b/vmware_nsx/services/lbaas/nsx_v3/l7policy_mgr.py @@ -0,0 +1,53 @@ +# Copyright 2017 VMware, Inc. +# All Rights Reserved +# +# 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 neutron_lib import exceptions as n_exc +from oslo_log import helpers as log_helpers +from oslo_log import log as logging + +from vmware_nsx._i18n import _ +from vmware_nsx.services.lbaas import base_mgr + +LOG = logging.getLogger(__name__) + + +class EdgeL7PolicyManager(base_mgr.Nsxv3LoadbalancerBaseManager): + @log_helpers.log_method_call + def __init__(self): + 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) + + @log_helpers.log_method_call + def create(self, context, policy): + self._l7policy_action(context, policy, 'create') + + @log_helpers.log_method_call + def update(self, context, old_policy, new_policy): + self._l7policy_action(context, new_policy, 'update') + + @log_helpers.log_method_call + def delete(self, context, policy): + self._l7policy_action(context, policy, 'delete', delete=True) diff --git a/vmware_nsx/services/lbaas/nsx_v3/l7rule_mgr.py b/vmware_nsx/services/lbaas/nsx_v3/l7rule_mgr.py new file mode 100644 index 0000000000..15bf273bfd --- /dev/null +++ b/vmware_nsx/services/lbaas/nsx_v3/l7rule_mgr.py @@ -0,0 +1,189 @@ +# Copyright 2017 VMware, Inc. +# All Rights Reserved +# +# 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 neutron_lib import exceptions as n_exc +from oslo_log import helpers as log_helpers +from oslo_log import log as logging + +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__) + + +class EdgeL7RuleManager(base_mgr.Nsxv3LoadbalancerBaseManager): + @log_helpers.log_method_call + def __init__(self): + super(EdgeL7RuleManager, self).__init__() + + @log_helpers.log_method_call + def _get_rule_match_conditions(self, rule): + match_conditions = [] + if rule.type == lb_const.L7_RULE_TYPE_COOKIE: + header_value = rule.key + '=' + rule.value + match_conditions.append( + {'type': 'LbHttpRequestHeaderCondition', + 'header_name': 'Cookie', + 'header_value': header_value}) + elif rule.type == lb_const.L7_RULE_TYPE_FILE_TYPE: + match_conditions.append( + {'type': 'LbHttpRequestUriCondition', + 'uri': '*.' + rule.value}) + elif rule.type == lb_const.L7_RULE_TYPE_HEADER: + match_conditions.append( + {'type': 'LbHttpRequestHeaderCondition', + 'header_name': rule.key, + 'header_value': rule.value}) + elif rule.type == lb_const.L7_RULE_TYPE_HOST_NAME: + match_conditions.append( + {'type': 'LbHttpRequestHeaderCondition', + 'header_name': 'Host', + 'header_value': rule.value}) + elif rule.type == lb_const.L7_RULE_TYPE_PATH: + match_conditions.append( + {'type': 'LbHttpRequestUriCondition', + '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) + + @log_helpers.log_method_call + def _convert_l7policy_to_rule(self, context, rule): + lb_id = rule.policy.listener.loadbalancer_id + body = {} + 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'] + body['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: + body['actions'] = [{'type': lb_const.LB_HTTP_REDIRECT_ACTION, + 'redirect_rul': l7policy.redirect_url}] + elif l7policy.action == lb_const.L7_POLICY_ACTION_REJECT: + body['actions'] = [{'type': lb_const.LB_REJECT_ACTION}] + else: + msg = (_('Invalid l7policy action: %(action)s') % + {'action': l7policy.action}) + raise n_exc.BadRequest(resource='lbaas-l7rule-create', + msg=msg) + return body + + @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_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)% 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) + + @log_helpers.log_method_call + def update(self, context, old_rule, new_rule): + self.lbv2_driver.l7rule.successful_completion(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: + rule_client.delete(rule_id) + except nsx_exc.NsxResourceNotFound: + msg = (_("LB rule cannot be found on nsx: %(rule)s") % + {'rule': rule_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 delete lb rule: %(rule)s') % + {'rule': rule.id}) + raise n_exc.BadRequest(resource='lbaas-l7rule-delete', + msg=msg) + try: + lb_vs = vs_client.get(vs_id) + if 'rule_ids' in lb_vs and rule_id in lb_vs['rule_ids']: + lb_vs['rule_ids'].remove(rule_id) + vs_client.update(vs_id, lb_vs) + 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) + + 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) diff --git a/vmware_nsx/services/lbaas/nsx_v3/lb_driver_v2.py b/vmware_nsx/services/lbaas/nsx_v3/lb_driver_v2.py index 223e509b2e..1dac1f9064 100644 --- a/vmware_nsx/services/lbaas/nsx_v3/lb_driver_v2.py +++ b/vmware_nsx/services/lbaas/nsx_v3/lb_driver_v2.py @@ -17,6 +17,8 @@ from oslo_log import helpers as log_helpers from oslo_log import log as logging from vmware_nsx.services.lbaas.nsx_v3 import healthmonitor_mgr as hm_mgr +from vmware_nsx.services.lbaas.nsx_v3 import l7policy_mgr +from vmware_nsx.services.lbaas.nsx_v3 import l7rule_mgr from vmware_nsx.services.lbaas.nsx_v3 import listener_mgr from vmware_nsx.services.lbaas.nsx_v3 import loadbalancer_mgr as lb_mgr from vmware_nsx.services.lbaas.nsx_v3 import member_mgr @@ -50,6 +52,8 @@ class EdgeLoadbalancerDriverV2(object): self.pool = pool_mgr.EdgePoolManager() self.member = member_mgr.EdgeMemberManager() self.healthmonitor = hm_mgr.EdgeHealthMonitorManager() + self.l7policy = l7policy_mgr.EdgeL7PolicyManager() + self.l7rule = l7rule_mgr.EdgeL7RuleManager() class DummyLoadbalancerDriverV2(object): diff --git a/vmware_nsx/services/lbaas/nsx_v3/pool_mgr.py b/vmware_nsx/services/lbaas/nsx_v3/pool_mgr.py index 762e029ec0..cf11d50ca6 100644 --- a/vmware_nsx/services/lbaas/nsx_v3/pool_mgr.py +++ b/vmware_nsx/services/lbaas/nsx_v3/pool_mgr.py @@ -46,9 +46,11 @@ class EdgePoolManager(base_mgr.Nsxv3LoadbalancerBaseManager): lb_const.LB_POOL_TYPE, pool.tenant_id, context.project_name) try: + snat_translation = {'type': "LbSnatAutoMap"} lb_pool = pool_client.create(display_name=pool_name, tags=tags, - algorithm=pool.lb_algorithm) + algorithm=pool.lb_algorithm, + snat_translation=snat_translation) except nsxlib_exc.ManagerError: self.lbv2_driver.pool.failed_completion(context, pool) msg = (_('Failed to create pool on NSX backend: %(pool)s') % diff --git a/vmware_nsx/tests/unit/services/lbaas/test_nsxv3_driver.py b/vmware_nsx/tests/unit/services/lbaas/test_nsxv3_driver.py index 0a6c537572..96c19f19e0 100644 --- a/vmware_nsx/tests/unit/services/lbaas/test_nsxv3_driver.py +++ b/vmware_nsx/tests/unit/services/lbaas/test_nsxv3_driver.py @@ -94,6 +94,14 @@ HM_BINDING = {'loadbalancer_id': LB_ID, 'hm_id': HM_ID, 'lb_monitor_id': LB_MONITOR_ID, 'lb_pool_id': LB_POOL_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, + 'lb_vs_id': LB_VS_ID, + 'lb_rule_id': LB_RULE_ID} class BaseTestEdgeLbaasV2(base.BaseTestCase): @@ -130,6 +138,22 @@ class BaseTestEdgeLbaasV2(base.BaseTestCase): name='member-mmm-mmm') self.hm = lb_models.HealthMonitor(HM_ID, LB_TENANT_ID, 'PING', 3, 3, 1, pool=self.pool, name='hm1') + self.l7policy = lb_models.L7Policy(L7POLICY_ID, LB_TENANT_ID, + name='policy-test', + description='policy-desc', + listener_id=LISTENER_ID, + action='REDIRECT_TO_POOL', + redirect_pool_id=LB_POOL_ID, + listener=self.listener, + position=1) + self.l7rule = lb_models.L7Rule(L7RULE_ID, LB_TENANT_ID, + l7policy_id=L7POLICY_ID, + compare_type='EQUAL_TO', + invert=False, + type='HEADER', + key='key1', + value='val1', + policy=self.l7policy) def tearDown(self): self._unpatch_lb_plugin(self.lbv2_driver, self._tested_entity) @@ -156,6 +180,8 @@ class BaseTestEdgeLbaasV2(base.BaseTestCase): 'pool').start() self.monitor_client = mock.patch.object(load_balancer, 'monitor').start() + self.rule_client = mock.patch.object(load_balancer, + 'rule').start() def _unpatch_lb_plugin(self, lb_plugin, manager): setattr(lb_plugin, manager, self.real_manager) @@ -487,7 +513,7 @@ class TestEdgeLbaasV2HealthMonitor(BaseTestEdgeLbaasV2): def test_update(self): new_hm = lb_models.HealthMonitor(HM_ID, LB_TENANT_ID, 'PING', 3, 3, 3, pool=self.pool) - self.edge_driver.healthmonitor.update(self.context, self.pool, new_hm) + self.edge_driver.healthmonitor.update(self.context, self.hm, new_hm) mock_successful_completion = ( self.lbv2_driver.health_monitor.successful_completion) @@ -517,3 +543,120 @@ class TestEdgeLbaasV2HealthMonitor(BaseTestEdgeLbaasV2): mock_successful_completion.assert_called_with(self.context, self.hm, delete=True) + + +class TestEdgeLbaasV2L7Policy(BaseTestEdgeLbaasV2): + def setUp(self): + super(TestEdgeLbaasV2L7Policy, self).setUp() + + @property + def _tested_entity(self): + return 'l7policy' + + def test_create(self): + self.edge_driver.l7policy.create(self.context, self.l7policy) + mock_successful_completion = ( + self.lbv2_driver.l7policy.successful_completion) + mock_successful_completion.assert_called_with( + self.context, self.l7policy, delete=False) + + def test_update(self): + new_l7policy = lb_models.L7Policy(L7POLICY_ID, LB_TENANT_ID, + name='new-policy', + listener_id=LISTENER_ID, + action='REJECT', + listener=self.listener, + position=1) + self.edge_driver.l7policy.update(self.context, self.l7policy, + new_l7policy) + mock_successful_completion = ( + self.lbv2_driver.l7policy.successful_completion) + mock_successful_completion.assert_called_with( + self.context, new_l7policy, delete=False) + + def test_delete(self): + self.edge_driver.l7policy.delete(self.context, self.l7policy) + mock_successful_completion = ( + self.lbv2_driver.l7policy.successful_completion) + mock_successful_completion.assert_called_with( + self.context, self.l7policy, delete=True) + + +class TestEdgeLbaasV2L7Rule(BaseTestEdgeLbaasV2): + def setUp(self): + super(TestEdgeLbaasV2L7Rule, self).setUp() + + @property + def _tested_entity(self): + 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', + ) 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_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_successful_completion = ( + self.lbv2_driver.l7rule.successful_completion) + mock_successful_completion.assert_called_with(self.context, + self.l7rule) + + def test_update(self): + new_l7rule = lb_models.L7Rule(L7RULE_ID, LB_TENANT_ID, + l7policy_id=L7POLICY_ID, + compare_type='STARTS_WITH', + invert=True, + type='COOKIE', + key='cookie1', + value='xxxxx', + policy=self.l7policy) + self.edge_driver.l7rule.update(self.context, self.l7rule, new_l7rule) + mock_successful_completion = ( + self.lbv2_driver.l7rule.successful_completion) + mock_successful_completion.assert_called_with( + self.context, new_l7rule) + + def test_delete(self): + with mock.patch.object(nsx_db, 'get_nsx_lbaas_l7rule_binding', + ) as mock_get_l7rule_binding, \ + mock.patch.object(self.rule_client, 'delete', + ) as mock_delete_rule, \ + mock.patch.object(self.vs_client, 'get', + ) as mock_get_vs, \ + mock.patch.object(self.vs_client, 'update', + ) as mock_update_vs, \ + mock.patch.object(nsx_db, 'delete_nsx_lbaas_l7rule_binding', + ) as mock_delete_l7rule_binding: + mock_get_l7rule_binding.return_value = L7RULE_BINDING + mock_get_vs.return_value = {'id': LB_VS_ID, + 'rule_ids': [LB_RULE_ID]} + + self.edge_driver.l7rule.delete(self.context, self.l7rule) + + mock_delete_rule.assert_called_with(LB_RULE_ID) + mock_update_vs.assert_called_with(LB_VS_ID, {'id': LB_VS_ID, + 'rule_ids': []}) + mock_delete_l7rule_binding.assert_called_with( + self.context.session, LB_ID, L7POLICY_ID, L7RULE_ID) + + mock_successful_completion = ( + self.lbv2_driver.l7rule.successful_completion) + mock_successful_completion.assert_called_with(self.context, + self.l7rule, + delete=True)