Merge "bug 1057844: improve floating-ip association checks"
This commit is contained in:
commit
6ea6ebe635
@ -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})
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user