def get_router_for_floatingip(self, context, internal_port, internal_subnet, external_network_id): """Find a router to handle the floating-ip association. :param internal_port: The port for the fixed-ip. :param internal_subnet: The subnet for the fixed-ip. :param external_network_id: The external network for floating-ip. :raises: ExternalGatewayForFloatingIPNotFound if no suitable router is found. """ router_port = l3_models.RouterPort gw_port = orm.aliased(models_v2.Port, name="gw_port") router_port_qry = context.session.query( router_port.router_id ).join(gw_port, gw_port.device_id == router_port.router_id).filter( gw_port.network_id == external_network_id, gw_port.device_owner == constants.DEVICE_OWNER_ROUTER_GW ).distinct() first_router_id = None for router in router_port_qry: if not first_router_id: first_router_id = router.router_id if first_router_id: return first_router_id raise l3_exc.ExternalGatewayForFloatingIPNotFound( subnet_id=internal_subnet['id'], external_network_id=external_network_id, port_id=internal_port['id'])
def test_negative_find_a_router_for_fip_port_forwarding( self, mock_get_subnet, mock_get_port, mock_get_router, mock_get_ip_subnet): fip_obj = mock.Mock() pf_dict = { 'internal_port_id': 'internal_neutron_port', 'internal_ip_address': '10.0.0.1' } port_dict = { 'id': 'ID', 'fixed_ips': [{ "subnet_id": "test-subnet-id", "ip_address": "10.0.0.1" }] } mock_get_port.return_value = port_dict mock_get_ip_subnet.return_value = None self.assertRaises( lib_exc.BadRequest, self.pf_plugin._find_a_router_for_fip_port_forwarding, self.ctxt, pf_dict, fip_obj) self.assertTrue(not mock_get_subnet.called) mock_get_ip_subnet.return_value = 'internal_subnet_id' mock_get_router.side_effect = ( lib_l3_exc.ExternalGatewayForFloatingIPNotFound( external_network_id=mock.Mock(), subnet_id=mock.Mock(), port_id=mock.Mock())) self.assertRaises( lib_exc.BadRequest, self.pf_plugin._find_a_router_for_fip_port_forwarding, self.ctxt, pf_dict, fip_obj) self.assertTrue(mock_get_subnet.called) ipv6_port_dict = { 'id': 'ID', 'fixed_ips': [{ "subnet_id": "test-subnet-id", "ip_address": "1::1" }] } mock_get_port.return_value = ipv6_port_dict self.assertRaises( lib_exc.BadRequest, self.pf_plugin._find_a_router_for_fip_port_forwarding, self.ctxt, pf_dict, fip_obj)
def get_router_for_floatingip( self, context, internal_port, internal_subnet, external_network_id): """Find a router to handle the floating-ip association. :param internal_port: The port for the fixed-ip. :param internal_subnet: The subnet for the fixed-ip. :param external_network_id: The external network for floating-ip. :raises: ExternalGatewayForFloatingIPNotFound if no suitable router is found. """ # REVISIT(yamamoto): The above docstring can be removed once # https://review.openstack.org/#/c/577029/ is released. # REVISIT(yamamoto): These direct manipulation of core-plugin db # resources is not ideal. gw_port = orm.aliased(models_v2.Port, name="gw_port") routerport_qry = context.session.query( l3_models.RouterPort.router_id, models_v2.IPAllocation.ip_address ).join( models_v2.Port, models_v2.IPAllocation ).filter( models_v2.Port.network_id == internal_port['network_id'], l3_models.RouterPort.port_type.in_( n_const.ROUTER_INTERFACE_OWNERS ), models_v2.IPAllocation.subnet_id == internal_subnet['id'] ).join( gw_port, gw_port.device_id == l3_models.RouterPort.router_id ).filter( gw_port.network_id == external_network_id, ).distinct() first_router_id = None for router_id, interface_ip in routerport_qry: if interface_ip == internal_subnet['gateway_ip']: return router_id if not first_router_id: first_router_id = router_id if first_router_id: return first_router_id raise l3_exc.ExternalGatewayForFloatingIPNotFound( subnet_id=internal_subnet['id'], external_network_id=external_network_id, port_id=internal_port['id'])
def _get_router_for_floatingip(self, context, internal_port, internal_subnet_id, external_network_id): subnet = self._core_plugin.get_subnet(context, internal_subnet_id) if not subnet['gateway_ip']: msg = (_('Cannot add floating IP to port on subnet %s ' 'which has no gateway_ip') % internal_subnet_id) raise n_exc.BadRequest(resource='floatingip', msg=msg) # Find routers(with router_id and interface address) that # connect given internal subnet and the external network. # Among them, if the router's interface address matches # with subnet's gateway-ip, return that router. # Otherwise return the first router. gw_port = orm.aliased(models_v2.Port, name="gw_port") routerport_qry = context.session.query( RouterPort.router_id, models_v2.IPAllocation.ip_address).join( models_v2.Port, models_v2.IPAllocation).filter( models_v2.Port.network_id == internal_port['network_id'], RouterPort.port_type.in_(nlib_const.ROUTER_INTERFACE_OWNERS), models_v2.IPAllocation.subnet_id == internal_subnet_id ).join(gw_port, gw_port.device_id == RouterPort.router_id).filter( gw_port.network_id == external_network_id).distinct() first_router_id = None for router_id, interface_ip in routerport_qry: if interface_ip == subnet['gateway_ip']: return router_id if not first_router_id: first_router_id = router_id if first_router_id: return first_router_id router_ids = self._find_routers_via_routes_for_floatingip( context, internal_port, internal_subnet_id, external_network_id) if router_ids: return router_ids[0] raise l3.ExternalGatewayForFloatingIPNotFound( subnet_id=internal_subnet_id, external_network_id=external_network_id, port_id=internal_port['id'])