diff --git a/vmware_nsx/services/lbaas/nsx_v3/implementation/lb_utils.py b/vmware_nsx/services/lbaas/nsx_v3/implementation/lb_utils.py index 92736d5a30..a4ee48cf01 100644 --- a/vmware_nsx/services/lbaas/nsx_v3/implementation/lb_utils.py +++ b/vmware_nsx/services/lbaas/nsx_v3/implementation/lb_utils.py @@ -87,6 +87,39 @@ def validate_lb_subnet(context, plugin, subnet_id): return False +def validate_lb_member_subnet(context, plugin, subnet_id, lb): + '''Validate LB member subnet before creating a member. + + The member subnet should belong to an external network or be connected + to the same T1 router as the Lb vip. + It will throw exception if the subnet doesn't meet this requirement. + + :param context: context + :param plugin: core plugin + :param subnet_id: loadbalancer's subnet id + :return: True if subnet meet requirement, otherwise return False + ''' + network = get_network_from_subnet(context, plugin, subnet_id) + if network.get('router:external'): + return True + member_router_id = get_router_from_network( + context, plugin, subnet_id) + lb_router_id = get_router_from_network( + context, plugin, lb['vip_subnet_id']) + if lb_router_id: + # Lb on non-external network. member must be on the same router + if lb_router_id == member_router_id: + return True + else: + return False + else: + # LB on external network. member subnet must have a router + if member_router_id: + return True + else: + return False + + def get_rule_match_conditions(policy): match_conditions = [] # values in rule have already been validated in LBaaS API, diff --git a/vmware_nsx/services/lbaas/nsx_v3/implementation/member_mgr.py b/vmware_nsx/services/lbaas/nsx_v3/implementation/member_mgr.py index 63c6cbec37..f571c4ba8e 100644 --- a/vmware_nsx/services/lbaas/nsx_v3/implementation/member_mgr.py +++ b/vmware_nsx/services/lbaas/nsx_v3/implementation/member_mgr.py @@ -112,11 +112,13 @@ class EdgeMemberManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager): lb_id = member['pool']['loadbalancer_id'] pool_id = member['pool']['id'] loadbalancer = member['pool']['loadbalancer'] - if not lb_utils.validate_lb_subnet(context, self.core_plugin, - member['subnet_id']): + if not lb_utils.validate_lb_member_subnet(context, self.core_plugin, + member['subnet_id'], + loadbalancer): completor(success=False) msg = (_('Cannot add member %(member)s to pool as member subnet ' - '%(subnet)s is neither public nor connected to router') % + '%(subnet)s is neither public nor connected to the LB ' + 'router') % {'member': member['id'], 'subnet': member['subnet_id']}) raise n_exc.BadRequest(resource='lbaas-subnet', msg=msg) 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 37f798642f..6083c6e116 100644 --- a/vmware_nsx/tests/unit/services/lbaas/test_nsxv3_driver.py +++ b/vmware_nsx/tests/unit/services/lbaas/test_nsxv3_driver.py @@ -488,7 +488,7 @@ class TestEdgeLbaasV2Member(BaseTestEdgeLbaasV2): return 'member' def test_create(self): - with mock.patch.object(lb_utils, 'validate_lb_subnet' + with mock.patch.object(lb_utils, 'validate_lb_member_subnet' ) as mock_validate_lb_subnet, \ mock.patch.object(self.lbv2_driver.plugin, 'get_pool_members' ) as mock_get_pool_members, \ @@ -538,7 +538,7 @@ class TestEdgeLbaasV2Member(BaseTestEdgeLbaasV2): delete=False) def test_create_lbs_no_router_gateway(self): - with mock.patch.object(lb_utils, 'validate_lb_subnet' + with mock.patch.object(lb_utils, 'validate_lb_member_subnet' ) as mock_validate_lb_subnet, \ mock.patch.object(self.lbv2_driver.plugin, 'get_pool_members' ) as mock_get_pool_members, \ @@ -571,6 +571,22 @@ class TestEdgeLbaasV2Member(BaseTestEdgeLbaasV2): self.context, self.member) + def test_create_member_different_router(self): + with mock.patch.object(self.lbv2_driver.plugin, 'get_pool_members' + ) as mock_get_pool_members, \ + mock.patch.object(lb_utils, 'get_network_from_subnet' + ) as mock_get_network, \ + mock.patch.object(lb_utils, 'get_router_from_network' + ) as mock_get_router: + mock_get_pool_members.return_value = [self.member] + mock_get_network.return_value = LB_NETWORK + mock_get_router.return_value = None + + self.assertRaises(n_exc.BadRequest, + self.edge_driver.member.create, + self.context, + self.member) + def test_update(self): new_member = lb_models.Member(MEMBER_ID, LB_TENANT_ID, POOL_ID, MEMBER_ADDRESS, 80, 2, pool=self.pool,