Merge "bug 1057844: improve floating-ip association checks"

This commit is contained in:
Jenkins 2012-11-21 05:37:58 +00:00 committed by Gerrit Code Review
commit 6ea6ebe635
3 changed files with 49 additions and 41 deletions

View File

@ -426,34 +426,35 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
'fixed_ip_address': floatingip['fixed_ip_address']}
return self._fields(res, fields)
def _get_router_for_internal_subnet(self, context, internal_port,
internal_subnet_id):
def _get_router_for_floatingip(self, context, internal_port,
internal_subnet_id,
external_network_id):
subnet_db = self._get_subnet(context, internal_subnet_id)
if not subnet_db['gateway_ip']:
msg = ('Cannot add floating IP to port on subnet %s '
'which has no gateway_ip' % internal_subnet_id)
raise q_exc.BadRequest(resource='floatingip', msg=msg)
#FIXME(danwent): can do join, but cannot use standard F-K syntax?
# just do it inefficiently for now
port_qry = context.session.query(models_v2.Port)
ports = port_qry.filter_by(network_id=internal_port['network_id'])
for p in ports:
ips = [ip['ip_address'] for ip in p['fixed_ips']]
if len(ips) != 1:
continue
fixed = p['fixed_ips'][0]
if (fixed['ip_address'] == subnet_db['gateway_ip'] and
fixed['subnet_id'] == internal_subnet_id):
router_qry = context.session.query(Router)
try:
router = router_qry.filter_by(id=p['device_id']).one()
return router['id']
except exc.NoResultFound:
pass
# find router interface ports on this network
router_intf_qry = context.session.query(models_v2.Port)
router_intf_ports = router_intf_qry.filter_by(
network_id=internal_port['network_id'],
device_owner=DEVICE_OWNER_ROUTER_INTF)
for intf_p in router_intf_ports:
if intf_p['fixed_ips'][0]['subnet_id'] == internal_subnet_id:
router_id = intf_p['device_id']
router_gw_qry = context.session.query(models_v2.Port)
has_gw_port = router_gw_qry.filter_by(
network_id=external_network_id,
device_id=router_id,
device_owner=DEVICE_OWNER_ROUTER_GW).count()
if has_gw_port:
return router_id
raise l3.ExternalGatewayForFloatingIPNotFound(
subnet_id=internal_subnet_id,
external_network_id=external_network_id,
port_id=internal_port['id'])
def get_assoc_data(self, context, fip, floating_network_id):
@ -501,9 +502,10 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
internal_ip_address = internal_port['fixed_ips'][0]['ip_address']
internal_subnet_id = internal_port['fixed_ips'][0]['subnet_id']
router_id = self._get_router_for_internal_subnet(context,
internal_port,
internal_subnet_id)
router_id = self._get_router_for_floatingip(context,
internal_port,
internal_subnet_id,
floating_network_id)
# confirm that this router has a floating
# ip enabled gateway with support for this floating IP network
try:
@ -526,17 +528,24 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
msg = "fixed_ip_address cannot be specified without a port_id"
raise q_exc.BadRequest(resource='floatingip', msg=msg)
if 'port_id' in fip and fip['port_id']:
port_qry = context.session.query(FloatingIP)
try:
port_qry.filter_by(fixed_port_id=fip['port_id']).one()
raise l3.FloatingIPPortAlreadyAssociated(
port_id=fip['port_id'])
except exc.NoResultFound:
pass
port_id, internal_ip_address, router_id = self.get_assoc_data(
context,
fip,
floatingip_db['floating_network_id'])
fip_qry = context.session.query(FloatingIP)
try:
fip_qry.filter_by(
fixed_port_id=fip['port_id'],
floating_network_id=floatingip_db['floating_network_id'],
fixed_ip_address=internal_ip_address).one()
raise l3.FloatingIPPortAlreadyAssociated(
port_id=fip['port_id'],
fip_id=floatingip_db['id'],
floating_ip_address=floatingip_db['floating_ip_address'],
fixed_ip=internal_ip_address,
net_id=floatingip_db['floating_network_id'])
except exc.NoResultFound:
pass
floatingip_db.update({'fixed_ip_address': internal_ip_address,
'fixed_port_id': port_id,
'router_id': router_id})

View File

@ -44,14 +44,16 @@ class FloatingIPNotFound(qexception.NotFound):
class ExternalGatewayForFloatingIPNotFound(qexception.NotFound):
message = _("Could not find an external network gateway reachable "
message = _("External network %(external_network_id)s is not reachable "
"from subnet %(subnet_id)s. Therefore, cannot associate "
"Port %(port_id)s with a Floating IP.")
class FloatingIPPortAlreadyAssociated(qexception.InUse):
message = _("Port %(port_id)s already has a floating IP"
" associated with it")
message = _("Cannot associate floating IP %(floating_ip_address)s "
"(%(fip_id)s) with port %(port_id)s "
"using fixed IP %(fixed_ip)s, as that fixed IP already "
"has a floating IP on external network %(net_id)s.")
class L3PortInUse(qexception.InUse):

View File

@ -978,16 +978,13 @@ class L3NatDBTestCase(test_db_plugin.QuantumDbPluginV2TestCase):
self.assertEquals(body['floatingip']['fixed_ip_address'], None)
self.assertEquals(body['floatingip']['router_id'], None)
def test_double_floating_assoc(self):
def test_two_fips_one_port_invalid_return_409(self):
with self.floatingip_with_assoc() as fip1:
with self.subnet() as s:
with self.floatingip_no_assoc(s) as fip2:
port_id = fip1['floatingip']['port_id']
body = self._update('floatingips',
fip2['floatingip']['id'],
{'floatingip':
{'port_id': port_id}},
expected_code=exc.HTTPConflict.code)
res = self._create_floatingip(
'json',
fip1['floatingip']['floating_network_id'],
fip1['floatingip']['port_id'])
self.assertEqual(res.status_int, exc.HTTPConflict.code)
def test_floating_ip_direct_port_delete_returns_409(self):
found = False